@kindgi/cli 0.1.4-rc.5 → 0.1.5-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -10
- package/dist/build/defaults.d.ts +3 -1
- package/dist/build/defaults.d.ts.map +1 -1
- package/dist/build/defaults.js +44 -1
- package/dist/build/defaults.js.map +1 -1
- package/dist/build/java-image.d.ts +31 -0
- package/dist/build/java-image.d.ts.map +1 -0
- package/dist/build/java-image.js +146 -0
- package/dist/build/java-image.js.map +1 -0
- package/dist/build/pack-root.d.ts +1 -31
- package/dist/build/pack-root.d.ts.map +1 -1
- package/dist/build/pack-root.js +22 -2
- package/dist/build/pack-root.js.map +1 -1
- package/dist/build/runners.d.ts +44 -0
- package/dist/build/runners.d.ts.map +1 -1
- package/dist/build/scala-image.d.ts +21 -0
- package/dist/build/scala-image.d.ts.map +1 -0
- package/dist/build/scala-image.js +150 -0
- package/dist/build/scala-image.js.map +1 -0
- package/dist/cli-pin.d.ts +16 -0
- package/dist/cli-pin.d.ts.map +1 -0
- package/dist/cli-pin.js +66 -0
- package/dist/cli-pin.js.map +1 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +9 -8
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/approvals.d.ts.map +1 -1
- package/dist/commands/approvals.js +30 -4
- package/dist/commands/approvals.js.map +1 -1
- package/dist/commands/artifacts.d.ts.map +1 -1
- package/dist/commands/artifacts.js +100 -37
- package/dist/commands/artifacts.js.map +1 -1
- package/dist/commands/auth.js +2 -2
- package/dist/commands/blocks.d.ts.map +1 -1
- package/dist/commands/blocks.js +5 -4
- package/dist/commands/blocks.js.map +1 -1
- package/dist/commands/build.d.ts +10 -2
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +109 -16
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/capabilities.d.ts.map +1 -1
- package/dist/commands/capabilities.js +37 -10
- package/dist/commands/capabilities.js.map +1 -1
- package/dist/commands/console.d.ts +21 -0
- package/dist/commands/console.d.ts.map +1 -0
- package/dist/commands/console.js +87 -0
- package/dist/commands/console.js.map +1 -0
- package/dist/commands/conversations.d.ts.map +1 -1
- package/dist/commands/conversations.js +13 -2
- package/dist/commands/conversations.js.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +2 -2
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts +11 -0
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +211 -39
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/doctor.d.ts +18 -5
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +421 -21
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/env-scoped.d.ts +44 -0
- package/dist/commands/env-scoped.d.ts.map +1 -0
- package/dist/commands/env-scoped.js +222 -0
- package/dist/commands/env-scoped.js.map +1 -0
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +85 -123
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/eval-runs.d.ts +9 -0
- package/dist/commands/eval-runs.d.ts.map +1 -1
- package/dist/commands/eval-runs.js +20 -19
- package/dist/commands/eval-runs.js.map +1 -1
- package/dist/commands/eval-suites.d.ts.map +1 -1
- package/dist/commands/eval-suites.js +16 -8
- package/dist/commands/eval-suites.js.map +1 -1
- package/dist/commands/exports.d.ts +3 -0
- package/dist/commands/exports.d.ts.map +1 -0
- package/dist/commands/exports.js +82 -0
- package/dist/commands/exports.js.map +1 -0
- package/dist/commands/feedback.d.ts.map +1 -1
- package/dist/commands/feedback.js +6 -5
- package/dist/commands/feedback.js.map +1 -1
- package/dist/commands/flows.d.ts.map +1 -1
- package/dist/commands/flows.js +2 -1
- package/dist/commands/flows.js.map +1 -1
- package/dist/commands/gate-policies.d.ts.map +1 -1
- package/dist/commands/gate-policies.js +2 -1
- package/dist/commands/gate-policies.js.map +1 -1
- package/dist/commands/guardrails.d.ts.map +1 -1
- package/dist/commands/guardrails.js +3 -2
- package/dist/commands/guardrails.js.map +1 -1
- package/dist/commands/helpers.js +5 -5
- package/dist/commands/helpers.js.map +1 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +14 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +254 -18
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/judge-classes.d.ts.map +1 -1
- package/dist/commands/judge-classes.js +11 -10
- package/dist/commands/judge-classes.js.map +1 -1
- package/dist/commands/judgments.d.ts.map +1 -1
- package/dist/commands/judgments.js +7 -6
- package/dist/commands/judgments.js.map +1 -1
- package/dist/commands/key.js +4 -4
- package/dist/commands/memory.d.ts.map +1 -1
- package/dist/commands/memory.js +277 -25
- package/dist/commands/memory.js.map +1 -1
- package/dist/commands/people.d.ts +3 -0
- package/dist/commands/people.d.ts.map +1 -0
- package/dist/commands/people.js +166 -0
- package/dist/commands/people.js.map +1 -0
- package/dist/commands/proposals.d.ts.map +1 -1
- package/dist/commands/proposals.js +390 -69
- package/dist/commands/proposals.js.map +1 -1
- package/dist/commands/provenance.d.ts.map +1 -1
- package/dist/commands/provenance.js +6 -7
- package/dist/commands/provenance.js.map +1 -1
- package/dist/commands/providers.d.ts.map +1 -1
- package/dist/commands/providers.js +46 -7
- package/dist/commands/providers.js.map +1 -1
- package/dist/commands/reviewers.d.ts.map +1 -1
- package/dist/commands/reviewers.js +3 -2
- package/dist/commands/reviewers.js.map +1 -1
- package/dist/commands/runs.d.ts.map +1 -1
- package/dist/commands/runs.js +24 -14
- package/dist/commands/runs.js.map +1 -1
- package/dist/commands/schedules.d.ts +3 -0
- package/dist/commands/schedules.d.ts.map +1 -0
- package/dist/commands/schedules.js +275 -0
- package/dist/commands/schedules.js.map +1 -0
- package/dist/commands/secrets.d.ts.map +1 -1
- package/dist/commands/secrets.js +10 -11
- package/dist/commands/secrets.js.map +1 -1
- package/dist/commands/service-accounts.d.ts +3 -0
- package/dist/commands/service-accounts.d.ts.map +1 -0
- package/dist/commands/service-accounts.js +175 -0
- package/dist/commands/service-accounts.js.map +1 -0
- package/dist/commands/skills.d.ts +1 -1
- package/dist/commands/skills.d.ts.map +1 -1
- package/dist/commands/skills.js +11 -4
- package/dist/commands/skills.js.map +1 -1
- package/dist/commands/sso.d.ts +6 -0
- package/dist/commands/sso.d.ts.map +1 -0
- package/dist/commands/sso.js +318 -0
- package/dist/commands/sso.js.map +1 -0
- package/dist/commands/tokens.d.ts +11 -0
- package/dist/commands/tokens.d.ts.map +1 -1
- package/dist/commands/tokens.js +144 -11
- package/dist/commands/tokens.js.map +1 -1
- package/dist/commands/tools.d.ts.map +1 -1
- package/dist/commands/tools.js +4 -3
- package/dist/commands/tools.js.map +1 -1
- package/dist/commands/unwired.d.ts.map +1 -1
- package/dist/commands/unwired.js +1 -30
- package/dist/commands/unwired.js.map +1 -1
- package/dist/commands/upgrade.d.ts +11 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +160 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/context.d.ts +7 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +1 -0
- package/dist/context.js.map +1 -1
- package/dist/dev/defaults.d.ts +28 -11
- package/dist/dev/defaults.d.ts.map +1 -1
- package/dist/dev/defaults.js +114 -35
- package/dist/dev/defaults.js.map +1 -1
- package/dist/dev/google-credentials.d.ts +50 -0
- package/dist/dev/google-credentials.d.ts.map +1 -0
- package/dist/dev/google-credentials.js +157 -0
- package/dist/dev/google-credentials.js.map +1 -0
- package/dist/dev/java-builder.d.ts +56 -0
- package/dist/dev/java-builder.d.ts.map +1 -0
- package/dist/dev/java-builder.js +204 -0
- package/dist/dev/java-builder.js.map +1 -0
- package/dist/dev/jvm-run-files.d.ts +29 -0
- package/dist/dev/jvm-run-files.d.ts.map +1 -0
- package/dist/dev/jvm-run-files.js +94 -0
- package/dist/dev/jvm-run-files.js.map +1 -0
- package/dist/dev/lines.d.ts +13 -0
- package/dist/dev/lines.d.ts.map +1 -0
- package/dist/dev/lines.js +24 -0
- package/dist/dev/lines.js.map +1 -0
- package/dist/dev/log-view.d.ts +116 -0
- package/dist/dev/log-view.d.ts.map +1 -0
- package/dist/dev/log-view.js +233 -0
- package/dist/dev/log-view.js.map +1 -0
- package/dist/dev/pack-code.d.ts +79 -4
- package/dist/dev/pack-code.d.ts.map +1 -1
- package/dist/dev/pack-code.js +262 -3
- package/dist/dev/pack-code.js.map +1 -1
- package/dist/dev/pack-env.d.ts.map +1 -1
- package/dist/dev/pack-env.js +4 -0
- package/dist/dev/pack-env.js.map +1 -1
- package/dist/dev/pack-service.d.ts +11 -1
- package/dist/dev/pack-service.d.ts.map +1 -1
- package/dist/dev/pack-service.js +56 -20
- package/dist/dev/pack-service.js.map +1 -1
- package/dist/dev/paths.d.ts +6 -0
- package/dist/dev/paths.d.ts.map +1 -1
- package/dist/dev/paths.js +8 -0
- package/dist/dev/paths.js.map +1 -1
- package/dist/dev/project-database.js +1 -1
- package/dist/dev/project-database.js.map +1 -1
- package/dist/dev/runners.d.ts +35 -9
- package/dist/dev/runners.d.ts.map +1 -1
- package/dist/dev/runtime-container.d.ts +10 -2
- package/dist/dev/runtime-container.d.ts.map +1 -1
- package/dist/dev/runtime-container.js +48 -20
- package/dist/dev/runtime-container.js.map +1 -1
- package/dist/dev/runtime-env.d.ts +10 -0
- package/dist/dev/runtime-env.d.ts.map +1 -1
- package/dist/dev/runtime-env.js +8 -4
- package/dist/dev/runtime-env.js.map +1 -1
- package/dist/dev/runtime-image.d.ts +1 -1
- package/dist/dev/runtime-image.js +1 -1
- package/dist/dev/scala-builder.d.ts +72 -0
- package/dist/dev/scala-builder.d.ts.map +1 -0
- package/dist/dev/scala-builder.js +347 -0
- package/dist/dev/scala-builder.js.map +1 -0
- package/dist/env/project-env.d.ts.map +1 -1
- package/dist/env/project-env.js +3 -1
- package/dist/env/project-env.js.map +1 -1
- package/dist/errors.d.ts +9 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +15 -0
- package/dist/errors.js.map +1 -1
- package/dist/help.d.ts +14 -0
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +55 -0
- package/dist/help.js.map +1 -1
- package/dist/init/dependency-specs.d.ts +26 -0
- package/dist/init/dependency-specs.d.ts.map +1 -1
- package/dist/init/dependency-specs.js +38 -0
- package/dist/init/dependency-specs.js.map +1 -1
- package/dist/init/java-augment.d.ts +24 -0
- package/dist/init/java-augment.d.ts.map +1 -0
- package/dist/init/java-augment.js +198 -0
- package/dist/init/java-augment.js.map +1 -0
- package/dist/init/mode-detect.d.ts +2 -2
- package/dist/init/mode-detect.d.ts.map +1 -1
- package/dist/init/mode-detect.js +12 -1
- package/dist/init/mode-detect.js.map +1 -1
- package/dist/init/scala-augment.d.ts +23 -0
- package/dist/init/scala-augment.d.ts.map +1 -0
- package/dist/init/scala-augment.js +213 -0
- package/dist/init/scala-augment.js.map +1 -0
- package/dist/init/template-files.d.ts +40 -2
- package/dist/init/template-files.d.ts.map +1 -1
- package/dist/init/template-files.js +56 -5
- package/dist/init/template-files.js.map +1 -1
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +30 -4
- package/dist/main.js.map +1 -1
- package/dist/open-url.d.ts +15 -0
- package/dist/open-url.d.ts.map +1 -0
- package/dist/open-url.js +41 -0
- package/dist/open-url.js.map +1 -0
- package/dist/package-manager.d.ts +10 -3
- package/dist/package-manager.d.ts.map +1 -1
- package/dist/package-manager.js +19 -1
- package/dist/package-manager.js.map +1 -1
- package/dist/providers/preset-loader.d.ts.map +1 -1
- package/dist/providers/preset-loader.js +9 -1
- package/dist/providers/preset-loader.js.map +1 -1
- package/dist/providers/presets/anthropic.json +35 -4
- package/dist/providers/presets/gemini-api.json +3 -0
- package/dist/providers/presets/gemini.json +3 -0
- package/dist/providers/presets/groq.json +1 -0
- package/dist/providers/presets/openai.json +36 -4
- package/dist/providers/presets/openrouter.json +6 -2
- package/dist/sdk-skills/kindgi-authoring-agents/SKILL.md +28 -4
- package/dist/sdk-skills/kindgi-authoring-flows/SKILL.md +1 -1
- package/dist/sdk-skills/kindgi-authoring-guardrails/SKILL.md +47 -3
- package/dist/sdk-skills/kindgi-authoring-mcp-servers/SKILL.md +7 -5
- package/dist/sdk-skills/kindgi-authoring-providers/SKILL.md +81 -52
- package/dist/sdk-skills/kindgi-authoring-tools/SKILL.md +27 -1
- package/dist/sdk-skills/kindgi-framework-feedback/SKILL.md +5 -4
- package/dist/sdk-skills/kindgi-getting-started/SKILL.md +1 -1
- package/dist/sdk-skills/kindgi-java-authoring-agents/SKILL.md +220 -0
- package/dist/sdk-skills/kindgi-java-authoring-flows/SKILL.md +390 -0
- package/dist/sdk-skills/kindgi-java-authoring-guardrails/SKILL.md +209 -0
- package/dist/sdk-skills/kindgi-java-authoring-tools/SKILL.md +334 -0
- package/dist/sdk-skills/kindgi-java-getting-started/SKILL.md +270 -0
- package/dist/sdk-skills/kindgi-python-authoring-agents/SKILL.md +23 -5
- package/dist/sdk-skills/kindgi-python-authoring-flows/SKILL.md +1 -1
- package/dist/sdk-skills/kindgi-python-authoring-guardrails/SKILL.md +10 -3
- package/dist/sdk-skills/kindgi-python-authoring-tools/SKILL.md +36 -5
- package/dist/sdk-skills/kindgi-python-getting-started/SKILL.md +2 -2
- package/dist/sdk-skills/kindgi-scala-authoring-agents/SKILL.md +217 -0
- package/dist/sdk-skills/kindgi-scala-authoring-flows/SKILL.md +357 -0
- package/dist/sdk-skills/kindgi-scala-authoring-guardrails/SKILL.md +199 -0
- package/dist/sdk-skills/kindgi-scala-authoring-tools/SKILL.md +302 -0
- package/dist/sdk-skills/kindgi-scala-getting-started/SKILL.md +302 -0
- package/dist/templates/java/.mvn/wrapper/maven-wrapper.properties +3 -0
- package/dist/templates/java/AGENTS.md +31 -0
- package/dist/templates/java/README.md.tmpl +69 -0
- package/dist/templates/java/gitignore +9 -0
- package/dist/templates/java/kindgi.config.json.tmpl +8 -0
- package/dist/templates/java/kindgiw +33 -0
- package/dist/templates/java/kindgiw.cmd +28 -0
- package/dist/templates/java/mvnw +295 -0
- package/dist/templates/java/pom.xml.tmpl +65 -0
- package/dist/templates/java/src/main/java/__PACKAGE__/agents/EchoAgent.java.tmpl +27 -0
- package/dist/templates/java/src/main/java/__PACKAGE__/flows/EchoFlow.java.tmpl +18 -0
- package/dist/templates/java/src/main/java/__PACKAGE__/guardrails/ResponseNotEmpty.java.tmpl +28 -0
- package/dist/templates/java/src/main/java/__PACKAGE__/tools/Echo.java.tmpl +22 -0
- package/dist/templates/java/src/main/java/__PACKAGE__/tools/Greet.java.tmpl +23 -0
- package/dist/templates/java/src/test/java/__PACKAGE__/ToolsTest.java.tmpl +30 -0
- package/dist/templates/minimal/README.md.tmpl +8 -14
- package/dist/templates/python/README.md.tmpl +6 -6
- package/dist/templates/sample/README.md.tmpl +7 -13
- package/dist/templates/scala/AGENTS.md +32 -0
- package/dist/templates/scala/README.md.tmpl +75 -0
- package/dist/templates/scala/build.sbt.tmpl +16 -0
- package/dist/templates/scala/gitignore +13 -0
- package/dist/templates/scala/kindgi.config.json.tmpl +8 -0
- package/dist/templates/scala/project/build.properties +1 -0
- package/dist/templates/scala/src/main/scala/__PACKAGE__/agents/EchoAgent.scala.tmpl +23 -0
- package/dist/templates/scala/src/main/scala/__PACKAGE__/flows/EchoFlow.scala.tmpl +16 -0
- package/dist/templates/scala/src/main/scala/__PACKAGE__/guardrails/ResponseNotEmpty.scala.tmpl +21 -0
- package/dist/templates/scala/src/main/scala/__PACKAGE__/tools/Echo.scala.tmpl +16 -0
- package/dist/templates/scala/src/main/scala/__PACKAGE__/tools/Greet.scala.tmpl +17 -0
- package/dist/templates/scala/src/test/scala/__PACKAGE__/ToolsSuite.scala.tmpl +23 -0
- package/package.json +13 -12
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kindgi-java-authoring-tools
|
|
3
|
+
description: >
|
|
4
|
+
Covers writing tools for a Kindgi pack in Java (`com.kindgi:kindgi-pack`):
|
|
5
|
+
`Tool.define(id)` as a `public static final` field, input and output
|
|
6
|
+
schemas from records (Jakarta Validation constraints become keywords) or
|
|
7
|
+
a JSON Schema map, `handler` and `asyncHandler`, `ToolContext` and
|
|
8
|
+
cancellation, secrets (`needsSpec`) and configuration, errors,
|
|
9
|
+
`mutating(false)` and effects, unit tests with `Tool.call`, and wiring a
|
|
10
|
+
tool onto an agent. Load this whenever you are authoring or editing code
|
|
11
|
+
in a Java pack's tools packages (a pack whose `kindgi.config.json` says
|
|
12
|
+
`"language": "java"`), defining a tool, or wiring one onto an agent.
|
|
13
|
+
Java agents are covered by kindgi-java-authoring-agents, getting started
|
|
14
|
+
by kindgi-java-getting-started.
|
|
15
|
+
type: core
|
|
16
|
+
library: "kindgi-pack (Java)"
|
|
17
|
+
version: "0.1.0"
|
|
18
|
+
sdk_version: "0.1.5-rc.0"
|
|
19
|
+
pack_languages: [java]
|
|
20
|
+
sources:
|
|
21
|
+
- sdks/java/kindgi-pack/README.md
|
|
22
|
+
- sdks/java/kindgi-pack/src/main/java/com/kindgi/pack/Tool.java
|
|
23
|
+
- sdks/java/kindgi-pack/src/main/java/com/kindgi/pack/ToolContext.java
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# Authoring Kindgi tools in Java
|
|
27
|
+
|
|
28
|
+
> **Running `kindgi`:** the pack pins its CLI (`"cli"` in
|
|
29
|
+
> `kindgi.config.json`), and `./kindgiw` runs that version, so every
|
|
30
|
+
> `kindgi <command>` below runs as `./kindgiw <command>` (`kindgiw.cmd` on
|
|
31
|
+
> Windows). Maven runs as `./mvnw` (or the app's own `mvn`).
|
|
32
|
+
>
|
|
33
|
+
> Java support is in preview: tested and supported, but the API may still
|
|
34
|
+
> change in 0.1.6 without the usual deprecation period.
|
|
35
|
+
|
|
36
|
+
A **tool** is a unit of work an agent (or a flow step) calls: typed input,
|
|
37
|
+
typed output, your code in between. In a Java pack it is a
|
|
38
|
+
`public static final Tool<I, O>` field of a class in a `tools` package
|
|
39
|
+
(`src/main/java/**/tools/**/*.java`; in an app, `**/kindgi/tools/**`). Kindgi
|
|
40
|
+
runs it in the pack's own JVM (the pack service) and calls it over HTTP; the
|
|
41
|
+
model sees its id, description and input schema.
|
|
42
|
+
|
|
43
|
+
Before writing one, establish what it should **do**: what it computes or
|
|
44
|
+
fetches, what the caller provides, what it returns. "Add a tool" is a
|
|
45
|
+
conversation opener. The pack's sample tools prove the runtime works; they
|
|
46
|
+
are not the shape to copy unless the user asks.
|
|
47
|
+
|
|
48
|
+
## A tool
|
|
49
|
+
|
|
50
|
+
```java
|
|
51
|
+
// src/main/java/acme/tools/VerifyCitation.java
|
|
52
|
+
package acme.tools;
|
|
53
|
+
|
|
54
|
+
import com.kindgi.pack.Tool;
|
|
55
|
+
import jakarta.validation.constraints.Pattern;
|
|
56
|
+
import jakarta.validation.constraints.Size;
|
|
57
|
+
import java.io.IOException;
|
|
58
|
+
import java.util.Map;
|
|
59
|
+
import org.jspecify.annotations.Nullable;
|
|
60
|
+
|
|
61
|
+
/** acme.verify-citation: checks a legal citation against the citator. */
|
|
62
|
+
public final class VerifyCitation {
|
|
63
|
+
public record Input(
|
|
64
|
+
@Size(min = 1) String citation,
|
|
65
|
+
@Pattern(regexp = "^(US|UK|EU)$") String jurisdiction) {}
|
|
66
|
+
|
|
67
|
+
public record Output(boolean found, @Nullable String canonicalCite) {}
|
|
68
|
+
|
|
69
|
+
public static final Tool<Input, Output> TOOL = Tool.define("acme.verify-citation")
|
|
70
|
+
.description("Verifies a legal citation against the citator; returns whether it resolves and its canonical form.")
|
|
71
|
+
.input(Input.class)
|
|
72
|
+
.output(Output.class)
|
|
73
|
+
.mutating(false)
|
|
74
|
+
.set("needsSpec", Map.of("secrets", Map.of("CITATOR_KEY", Map.of("type", "string", "minLength", 20))))
|
|
75
|
+
.handler((input, ctx) ->
|
|
76
|
+
verify(input, (String) ctx.secrets().get("CITATOR_KEY"), System.getenv("CITATOR_URL")));
|
|
77
|
+
|
|
78
|
+
/** The tool's work, with what it reads from its context and the environment passed in: a test calls it. */
|
|
79
|
+
public static Output verify(Input input, String key, String citatorUrl) throws IOException, InterruptedException {
|
|
80
|
+
String hit = Citator.lookup(citatorUrl, key, input.citation(), input.jurisdiction());
|
|
81
|
+
return new Output(hit != null, hit);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private VerifyCitation() {}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```java
|
|
89
|
+
// src/main/java/acme/tools/Citator.java
|
|
90
|
+
package acme.tools;
|
|
91
|
+
|
|
92
|
+
import java.io.IOException;
|
|
93
|
+
import java.net.URI;
|
|
94
|
+
import java.net.URLEncoder;
|
|
95
|
+
import java.net.http.HttpClient;
|
|
96
|
+
import java.net.http.HttpRequest;
|
|
97
|
+
import java.net.http.HttpResponse;
|
|
98
|
+
import java.nio.charset.StandardCharsets;
|
|
99
|
+
import org.jspecify.annotations.Nullable;
|
|
100
|
+
|
|
101
|
+
/** The citator's API. Package-private: a helper, not a primitive. */
|
|
102
|
+
final class Citator {
|
|
103
|
+
private static final HttpClient HTTP = HttpClient.newHttpClient();
|
|
104
|
+
|
|
105
|
+
static @Nullable String lookup(String baseUrl, String key, String citation, String jurisdiction)
|
|
106
|
+
throws IOException, InterruptedException {
|
|
107
|
+
String query = "q=" + URLEncoder.encode(citation, StandardCharsets.UTF_8) + "&j=" + jurisdiction;
|
|
108
|
+
HttpRequest request = HttpRequest.newBuilder(URI.create(baseUrl + "/lookup?" + query))
|
|
109
|
+
.header("Authorization", "Bearer " + key)
|
|
110
|
+
.build();
|
|
111
|
+
HttpResponse<String> response = HTTP.send(request, HttpResponse.BodyHandlers.ofString());
|
|
112
|
+
return response.statusCode() == 200 ? response.body() : null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private Citator() {}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
- **Where it lives:** a `public static final` field of a class in a `tools`
|
|
120
|
+
package. The indexer loads the class and takes the tools its static fields
|
|
121
|
+
hold. A tool built in a method, or held by an instance field, is never
|
|
122
|
+
found.
|
|
123
|
+
- **Id:** `<pack-id>.<tool-name>`, kebab-case, dot-namespaced.
|
|
124
|
+
- **Description:** what it does and returns. The model reads it to decide
|
|
125
|
+
when to call the tool. It isn't enforced, so never leave it out.
|
|
126
|
+
- **Version:** the pack's (`pack.version`), or `.version("1.2.0")` (an exact
|
|
127
|
+
semver).
|
|
128
|
+
- **Schemas:** from the records `input(…)` and `output(…)` name. A record's
|
|
129
|
+
components are the object's properties, by their Jackson names
|
|
130
|
+
(`@JsonProperty("canonicalCite")` renames one). Unknown properties are
|
|
131
|
+
refused unless the type says `@JsonIgnoreProperties(ignoreUnknown = true)`.
|
|
132
|
+
The input must be an **object**: a model calls a tool with an object of
|
|
133
|
+
arguments.
|
|
134
|
+
|
|
135
|
+
| In Java | In the schema |
|
|
136
|
+
|---|---|
|
|
137
|
+
| `String`, `int`/`long`, `double`/`BigDecimal`, `boolean` | `string`, `integer`, `number`, `boolean` |
|
|
138
|
+
| `@Nullable T`, `Optional<T>` | not required; `null` allowed |
|
|
139
|
+
| `@JsonProperty(defaultValue = "1")` | `default: 1`, not required; the service fills it in |
|
|
140
|
+
| `List<T>`, `Set<T>`, `T[]`; `Map<String, T>` | `array`; `object` with `additionalProperties` |
|
|
141
|
+
| an enum; `UUID`, `Instant`, `LocalDate`, `URI` | `enum`; `string` with its `format` |
|
|
142
|
+
| `@JsonPropertyDescription` | `description` |
|
|
143
|
+
| `@Size`, `@Min`, `@Max`, `@Pattern`, `@Email`, `@NotBlank`, `@Positive`, … | the matching keywords |
|
|
144
|
+
|
|
145
|
+
A type that can't be a schema (a recursive record, a map with non-string
|
|
146
|
+
keys) is a file error naming the property. When a type can't say it, pass
|
|
147
|
+
the schema itself, `input(Map.of("type", "object", …))`, and the handler
|
|
148
|
+
gets a `Map`.
|
|
149
|
+
- **Handler:** `(input, ctx) -> output`. It may throw. It runs on a thread of
|
|
150
|
+
its own, so blocking I/O is fine. A handler built on futures uses
|
|
151
|
+
`asyncHandler((input, ctx) -> stage)` and returns a `CompletionStage`; the
|
|
152
|
+
service awaits it.
|
|
153
|
+
- **Validation:** before the handler runs, the input is checked against the
|
|
154
|
+
schema (its defaults filled in). Then what the handler returns is checked
|
|
155
|
+
against the output schema. A bad input comes back as
|
|
156
|
+
`input-validation-failed`, naming the field (a bad output as
|
|
157
|
+
`output-validation-failed`). The agent's `toolErrors` policy decides
|
|
158
|
+
whether the model gets to fix the call.
|
|
159
|
+
|
|
160
|
+
## `ToolContext`
|
|
161
|
+
|
|
162
|
+
- `ctx.tenantId()`: the tenant the call is for. Key per-tenant state by it.
|
|
163
|
+
- `ctx.runId()`: the run (an agent turn or a flow step) the call belongs to.
|
|
164
|
+
- `ctx.requestId()`: this call, such as the model's tool-call id. Useful for
|
|
165
|
+
logs and idempotency keys.
|
|
166
|
+
- `ctx.projectId()`, `ctx.orgId()`: the run's project, and its org (`null`
|
|
167
|
+
when it has none). The runtime sets them from the run, never from the
|
|
168
|
+
input. To check an id the input names, compare it with these.
|
|
169
|
+
- `ctx.cancellation()` fires when the call's deadline passes (120 s by
|
|
170
|
+
default) or the caller goes away. The handler's thread is interrupted too,
|
|
171
|
+
so a blocking wait ends. A loop checks `isCancelled()` or calls
|
|
172
|
+
`throwIfCancelled()`. Work started elsewhere (a request, a job) stops with
|
|
173
|
+
`onCancel(action)`.
|
|
174
|
+
- `ctx.secrets()`: the secrets the tool declares (below). Printing the
|
|
175
|
+
context shows their names, never their values.
|
|
176
|
+
- `ctx.env()`, `ctx.config()`: **reserved, empty today**.
|
|
177
|
+
|
|
178
|
+
## Configuration and secrets
|
|
179
|
+
|
|
180
|
+
A secret that belongs to the tenant, such as an API key a customer gives
|
|
181
|
+
you, is declared with `set("needsSpec", …)` and read from `ctx.secrets()`, as
|
|
182
|
+
above. The runtime resolves every declared secret on every call, for the
|
|
183
|
+
call's tenant, in its env (`KINDGI_ENV`; under `kindgi dev`, `local`: the
|
|
184
|
+
pack's `.env` and `.env.local`). It checks each against its schema, and fails
|
|
185
|
+
the call, naming the secret, when one is missing or doesn't match. Every
|
|
186
|
+
declared secret is required.
|
|
187
|
+
|
|
188
|
+
Everything else comes from the process environment: `System.getenv("CITATOR_URL")`.
|
|
189
|
+
Under `kindgi dev`, the pack service gets the pack's `.env` and `.env.local`,
|
|
190
|
+
and restarts when they change. Nothing else from your shell reaches it
|
|
191
|
+
except `PATH`, `HOME` and `TMPDIR`; `MAVEN_ARGS` and `MAVEN_OPTS` reach Maven
|
|
192
|
+
only. Put a secret there by hand, or with
|
|
193
|
+
`./kindgiw secrets set NAME --env=local --scope=tenant` (a no-echo prompt),
|
|
194
|
+
and keep the env files out of git. A deployed service names the variables
|
|
195
|
+
it needs in `kindgi.config.json`: `"env": {"required": ["DATABASE_URL"],
|
|
196
|
+
"optional": ["SENTRY_DSN"]}`. Without a required one it isn't ready.
|
|
197
|
+
`KINDGI_*` names are Kindgi's own and never reach pack code.
|
|
198
|
+
|
|
199
|
+
## Errors and output
|
|
200
|
+
|
|
201
|
+
- Throw for a failure: the call fails with `handler-throw` and the
|
|
202
|
+
exception's message. In an agent turn, the model sees the failure only
|
|
203
|
+
when the agent's `toolErrors` policy includes `tool-error`, so retrying
|
|
204
|
+
must be safe for that tool.
|
|
205
|
+
- What the handler logs (your app's logger, `System.err`) goes to the pack
|
|
206
|
+
service's output (`kindgi dev` shows it as `[pack] …`), never into a
|
|
207
|
+
result.
|
|
208
|
+
|
|
209
|
+
## Other declarations
|
|
210
|
+
|
|
211
|
+
**`mutating(false)`** declares a tool read-only: it changes nothing outside
|
|
212
|
+
itself (a lookup, a search, a calculation). A dry run
|
|
213
|
+
(`./kindgiw runs start --dry-run`) runs it. Leave it unset for anything that
|
|
214
|
+
writes, sends, charges or deletes: such a tool stops a dry run. It's also
|
|
215
|
+
the tool's approval default: an agent that turns approval gates on
|
|
216
|
+
(`conversationPolicy.hitl`) asks before any tool that isn't read-only on its
|
|
217
|
+
first use.
|
|
218
|
+
|
|
219
|
+
`effect(kind, resource)` declares a side effect, such as
|
|
220
|
+
`.effect("writes", "db:ledger")`. A dry run also stops at a tool with a
|
|
221
|
+
`writes`, `deletes`, `spawns-run`, `emits-event` or `external-side-effect`
|
|
222
|
+
effect. `set(field, value)` sets the index entry's other fields: `needs`,
|
|
223
|
+
`needsSpec`, `sandbox`, `limits`, `network`. They are recorded for policy and
|
|
224
|
+
review, so declare what the tool really does.
|
|
225
|
+
|
|
226
|
+
Java has no HTTP-tool form (TypeScript's `kind: 'http'`). A tool that calls
|
|
227
|
+
an HTTP API is a handler with `java.net.http.HttpClient`, as above.
|
|
228
|
+
|
|
229
|
+
## Testing
|
|
230
|
+
|
|
231
|
+
`Tool.call(input, ctx)` runs the handler with the input as given (no schema
|
|
232
|
+
check). `ToolContext.forTest()` is a context with a test tenant and run and
|
|
233
|
+
nothing else; `new ToolContext(…)` builds one with secrets:
|
|
234
|
+
|
|
235
|
+
```java
|
|
236
|
+
ToolContext ctx = new ToolContext("t-test", "run-test", null, null, null,
|
|
237
|
+
Map.of(), Map.of("CITATOR_KEY", "test-key-of-twenty-chars"), Map.of(), Map.of(), new Cancellation());
|
|
238
|
+
Greet.Output out = Greet.TOOL.call(new Greet.Input("Ada", "Hi"), ctx);
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
A Java test can't set an environment variable, so a handler that reads one
|
|
242
|
+
(`CITATOR_URL`) and calls a service is tested through the method it calls,
|
|
243
|
+
with a stub server:
|
|
244
|
+
|
|
245
|
+
```java
|
|
246
|
+
// src/test/java/acme/VerifyCitationTest.java
|
|
247
|
+
package acme;
|
|
248
|
+
|
|
249
|
+
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
250
|
+
|
|
251
|
+
import acme.tools.VerifyCitation;
|
|
252
|
+
import com.sun.net.httpserver.HttpServer;
|
|
253
|
+
import java.net.InetSocketAddress;
|
|
254
|
+
import org.junit.jupiter.api.Test;
|
|
255
|
+
|
|
256
|
+
class VerifyCitationTest {
|
|
257
|
+
@Test
|
|
258
|
+
void anUnknownCitationIsNotFound() throws Exception {
|
|
259
|
+
HttpServer citator = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
|
|
260
|
+
citator.createContext("/lookup", exchange -> {
|
|
261
|
+
exchange.sendResponseHeaders(404, -1);
|
|
262
|
+
exchange.close();
|
|
263
|
+
});
|
|
264
|
+
citator.start();
|
|
265
|
+
try {
|
|
266
|
+
String url = "http://127.0.0.1:" + citator.getAddress().getPort();
|
|
267
|
+
assertFalse(VerifyCitation.verify(new VerifyCitation.Input("1 U.S. 1", "US"), "test-key", url).found());
|
|
268
|
+
} finally {
|
|
269
|
+
citator.stop(0);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
`./mvnw test` runs the tests (`*Test.java`, `*IT.java` and anything under
|
|
276
|
+
`src/test/` are never indexed). To see the schemas Kindgi derives:
|
|
277
|
+
|
|
278
|
+
```sh
|
|
279
|
+
./mvnw -q compile dependency:build-classpath -Dmdep.outputFile=target/classpath.txt
|
|
280
|
+
java -cp "target/classes:$(cat target/classpath.txt)" com.kindgi.pack.Main index --pack-dir .
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Wiring the tool onto an agent
|
|
284
|
+
|
|
285
|
+
Pass the `Tool`, which pins that tool's version:
|
|
286
|
+
|
|
287
|
+
```java
|
|
288
|
+
Agent.define("acme.brief-writer")
|
|
289
|
+
// …
|
|
290
|
+
.tool(VerifyCitation.TOOL)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
A tool of another pack is `.tool("other.lookup", "^1.0.0")`: its id and a
|
|
294
|
+
semver **range**, and the highest active version matching it is picked at
|
|
295
|
+
turn start. In a flow, `toolNode("verify", VerifyCitation.TOOL)` runs it.
|
|
296
|
+
|
|
297
|
+
## Iterating
|
|
298
|
+
|
|
299
|
+
Save the file. `kindgi dev` recompiles with Maven, and the next call runs the
|
|
300
|
+
new code. A compile error is reported as `file:line:col`, and the last good
|
|
301
|
+
code keeps serving. Bump the version when callers' contract changes (a
|
|
302
|
+
removed field, a narrower type), not on every save.
|
|
303
|
+
|
|
304
|
+
## Common mistakes
|
|
305
|
+
|
|
306
|
+
1. **Copying the sample tool's shape without asking what the tool should do.**
|
|
307
|
+
2. **A tool that isn't a `static final` field.** An instance field, a local
|
|
308
|
+
variable or a method's return value is never indexed.
|
|
309
|
+
3. **A public class in a `tools` package that defines no tool.** It's a file
|
|
310
|
+
error, so a forgotten `static` can't drop a tool silently. Make a helper
|
|
311
|
+
package-private, or a record, an enum or an interface.
|
|
312
|
+
4. **No description.** The model can't tell when to call the tool.
|
|
313
|
+
5. **Reading `ctx.env()` or `ctx.config()`, or an undeclared secret.** The
|
|
314
|
+
first two are empty, and `ctx.secrets()` holds only what `needsSpec`
|
|
315
|
+
declares. Use `System.getenv` for the rest.
|
|
316
|
+
6. **A non-object input** (`input(String.class)`). The input is a record, a
|
|
317
|
+
bean, or an object schema.
|
|
318
|
+
7. **A class the tool uses with `test` or `provided` scope.** It works under
|
|
319
|
+
`kindgi dev` and fails in the image, which copies the runtime classpath
|
|
320
|
+
only. Use `compile` or `runtime` scope.
|
|
321
|
+
8. **A read-only tool without `mutating(false)`.** A dry run stops at it, and
|
|
322
|
+
an approval gate asks before it on first use.
|
|
323
|
+
9. **`mutating(false)` on a tool that writes.** A dry run then runs it for
|
|
324
|
+
real.
|
|
325
|
+
10. **A Jackson module registered only in code, on your own `ObjectMapper`.**
|
|
326
|
+
kindgi-pack finds modules as `findAndRegisterModules()` does, through
|
|
327
|
+
`META-INF/services`. Declare it there, or the tool's input and schema
|
|
328
|
+
won't see it.
|
|
329
|
+
|
|
330
|
+
## When the framework itself is the problem
|
|
331
|
+
|
|
332
|
+
If the bug is in Kindgi or kindgi-pack (a schema derived wrong, a misleading
|
|
333
|
+
error, the pack service misbehaving) and not in the tool's code, load
|
|
334
|
+
`kindgi-framework-feedback` and file it with `./kindgiw feedback write`.
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kindgi-java-getting-started
|
|
3
|
+
description: >
|
|
4
|
+
Getting a Java Kindgi pack running: what a pack is, scaffolding one
|
|
5
|
+
(`kindgi init <name> --template=java`) or adding Kindgi to an existing
|
|
6
|
+
Maven app (`kindgi.config.json`, discovery under `kindgi` packages),
|
|
7
|
+
`./kindgiw dev`, the first agent run, connecting a real model, flows,
|
|
8
|
+
calling the Kindgi API from Java (`com.kindgi:kindgi-client`), and
|
|
9
|
+
building an image. Load this when a Maven project has no
|
|
10
|
+
`kindgi.config.json` yet and the user asks to "add Kindgi", "make an
|
|
11
|
+
agent", "set up a pack", or when you are orienting in a Java pack
|
|
12
|
+
(`kindgi.config.json` with `"language": "java"`) for the first time.
|
|
13
|
+
Authoring tools, guardrails, agents and flows is covered by
|
|
14
|
+
kindgi-java-authoring-tools, kindgi-java-authoring-guardrails,
|
|
15
|
+
kindgi-java-authoring-agents and kindgi-java-authoring-flows; models by
|
|
16
|
+
kindgi-authoring-providers.
|
|
17
|
+
type: core
|
|
18
|
+
library: "kindgi-pack (Java)"
|
|
19
|
+
version: "0.1.0"
|
|
20
|
+
sdk_version: "0.1.5-rc.0"
|
|
21
|
+
pack_languages: [java]
|
|
22
|
+
sources:
|
|
23
|
+
- sdks/java/kindgi-pack/README.md
|
|
24
|
+
- sdks/java/README.md
|
|
25
|
+
- site/src/content/docs/start/quickstart-java.md
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# Getting started with Kindgi in Java
|
|
29
|
+
|
|
30
|
+
> **Running `kindgi`:** the pack pins its CLI (`"cli"` in
|
|
31
|
+
> `kindgi.config.json`), as Maven's wrapper pins Maven. `./kindgiw` runs that
|
|
32
|
+
> version (`kindgiw.cmd` on Windows): through Node's `npx` when Node is
|
|
33
|
+
> installed, else `uvx`. So every `kindgi <command>` below runs as
|
|
34
|
+
> `./kindgiw <command>`, and `./kindgiw upgrade` moves the pin.
|
|
35
|
+
>
|
|
36
|
+
> **Preview:** Java and Scala support is tested and supported, but its API
|
|
37
|
+
> may still change in 0.1.6 without the usual deprecation period.
|
|
38
|
+
|
|
39
|
+
## What a pack is
|
|
40
|
+
|
|
41
|
+
A **pack** is a project Kindgi indexes and runs. Its config is
|
|
42
|
+
`kindgi.config.json` (`"language": "java"`). Its primitives are
|
|
43
|
+
`public static final` fields of classes in four kinds of packages:
|
|
44
|
+
|
|
45
|
+
- **Tools** (`…/tools/…`, `Tool.define`): your Java code an agent or flow
|
|
46
|
+
calls.
|
|
47
|
+
- **Guardrails** (`…/guardrails/…`, `Guardrail.define`): checks over an
|
|
48
|
+
agent's turn.
|
|
49
|
+
- **Agents** (`…/agents/…`, `Agent.define`): data. Instructions, tools,
|
|
50
|
+
capabilities. The model runs in Kindgi.
|
|
51
|
+
- **Flows** (`…/flows/…`, `Flow.define`): data. Steps (tool or agent nodes)
|
|
52
|
+
and the edges between them.
|
|
53
|
+
|
|
54
|
+
Kindgi runs the tools and checks in the pack's own JVM (the pack service,
|
|
55
|
+
`com.kindgi:kindgi-pack`) and calls them over HTTP. Everything else runs in
|
|
56
|
+
the Kindgi runtime. In those packages, a helper is a package-private class,
|
|
57
|
+
a record, an enum or an interface. A public class that defines nothing is
|
|
58
|
+
an error, so a forgotten `static` can't drop a tool silently. Tests
|
|
59
|
+
(`*Test.java`, `*IT.java`, `src/test/`) are never primitives.
|
|
60
|
+
|
|
61
|
+
## Scaffold a new pack
|
|
62
|
+
|
|
63
|
+
You need a JDK 17 or later (`JAVA_HOME`). Maven comes with the pack
|
|
64
|
+
(`./mvnw`).
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
npx --yes @kindgi/cli@0.1 init my-pack --template=java # or: uvx --from "kindgi-cli>=0.1,<0.2" kindgi init …
|
|
68
|
+
cd my-pack
|
|
69
|
+
./mvnw test # the template's tests: the tools, called directly
|
|
70
|
+
./kindgiw dev # boots Kindgi locally and runs this pack, recompiling on save
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`kindgi dev` needs Docker and Postgres. It starts Postgres in Docker unless
|
|
74
|
+
`KINDGI_DATABASE_URL` points at yours. It checks the JDK (`JAVA_HOME`'s, or
|
|
75
|
+
`dev.javaHome` in `kindgi.config.json`) and Maven (the pack's `mvnw`, or
|
|
76
|
+
`dev.maven`, such as `["mvn", "-s", "settings.xml"]`). Maven compiles the
|
|
77
|
+
pack, the Java indexer reads it, and a save recompiles. A compile error is
|
|
78
|
+
reported as `file:line:col`, and the last good code keeps serving.
|
|
79
|
+
`MAVEN_ARGS` and `MAVEN_OPTS` reach Maven, never the pack.
|
|
80
|
+
|
|
81
|
+
## Add Kindgi to an existing Maven app
|
|
82
|
+
|
|
83
|
+
In the app's directory (where its `pom.xml` is):
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
npx --yes @kindgi/cli@0.1 init # --pack-id=<id> if the app's artifactId doesn't make one
|
|
87
|
+
./kindgiw dev
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`init` writes `kindgi.config.json`:
|
|
91
|
+
- the pack id, from the app's `artifactId`, and its version;
|
|
92
|
+
- the CLI version it pins (`"cli"`, which `./kindgiw` runs, also written);
|
|
93
|
+
- discovery under `kindgi` packages (`src/main/java/**/kindgi/tools/**/*.java`
|
|
94
|
+
and so on), so the app's own `tools` packages are never taken for
|
|
95
|
+
Kindgi's.
|
|
96
|
+
|
|
97
|
+
It leaves `pom.xml` alone, and prints the `com.kindgi:kindgi-pack`
|
|
98
|
+
dependency to add (from Maven Central, at the CLI's version). It also adds
|
|
99
|
+
these skills and `.gitignore` entries. An app with both a `package.json` and
|
|
100
|
+
a `pom.xml` gets a TypeScript pack unless you pass `--template=java`.
|
|
101
|
+
|
|
102
|
+
A tool there is a class in a `kindgi.tools` package under the app's own
|
|
103
|
+
(`com.acme.app.kindgi.tools`), and calls the app's code directly. A class a
|
|
104
|
+
tool uses must be on the runtime classpath (`compile` or `runtime` scope,
|
|
105
|
+
not `test` or `provided`): the image copies the runtime dependencies only.
|
|
106
|
+
`kindgi dev` reads the app's `.env` and `.env.local`: keys already there
|
|
107
|
+
reach the tools as environment variables.
|
|
108
|
+
|
|
109
|
+
## Layout of the template
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
my-pack/
|
|
113
|
+
├── kindgi.config.json # "language": "java", the pack's id and version, the CLI it pins
|
|
114
|
+
├── pom.xml # com.kindgi:kindgi-pack, Java 17
|
|
115
|
+
├── mvnw, .mvn/ # the Maven wrapper
|
|
116
|
+
├── kindgiw, kindgiw.cmd # the Kindgi CLI wrapper
|
|
117
|
+
├── src/main/java/mypack/
|
|
118
|
+
│ ├── tools/Echo.java, tools/Greet.java # Tool.define(...)
|
|
119
|
+
│ ├── guardrails/ResponseNotEmpty.java # Guardrail.define(...)
|
|
120
|
+
│ ├── agents/EchoAgent.java # Agent.define(...)
|
|
121
|
+
│ └── flows/EchoFlow.java # Flow.define(...)
|
|
122
|
+
├── src/test/java/mypack/ToolsTest.java # the tools, called directly
|
|
123
|
+
└── .claude/skills/ # these skills (`./kindgiw skills sync` refreshes them)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The package comes from the pack's id (`my-pack` becomes `mypack`).
|
|
127
|
+
`kindgi.config.json` also takes `discovery`, `dev`, `env`, `environments`,
|
|
128
|
+
`image` and `providers`.
|
|
129
|
+
|
|
130
|
+
## First run
|
|
131
|
+
|
|
132
|
+
With `kindgi dev` running, from another terminal in the pack directory:
|
|
133
|
+
|
|
134
|
+
```sh
|
|
135
|
+
./kindgiw runs start --agent=my-pack.echo-agent --input='{"userMessage":"Ada"}'
|
|
136
|
+
./kindgiw runs start --flow=my-pack.echo-flow --input='{"message":"Ada"}'
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The agent's answer comes from `dev-echo`, a **fallback** provider a new pack
|
|
140
|
+
gets: no model, no key. It calls the agent's first tool with
|
|
141
|
+
`{"message": <userMessage>}` and replies "⚠ dev-echo isn't a real model: …",
|
|
142
|
+
then "Tool responded: …". The turn carries the `fallback-provider` and
|
|
143
|
+
`dev-echo-not-a-model` warnings. It can't fill in any other tool's input,
|
|
144
|
+
and it can't give a typed answer. For a real model, store an LLM provider's
|
|
145
|
+
key and register its preset (Anthropic below; `./kindgiw providers presets`
|
|
146
|
+
lists OpenAI, Gemini, Groq and OpenRouter too):
|
|
147
|
+
|
|
148
|
+
```sh
|
|
149
|
+
./kindgiw secrets set ANTHROPIC_API_KEY --env=local --scope=tenant # no-echo prompt; writes .env.local
|
|
150
|
+
./kindgiw providers register --preset=anthropic
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
It takes over at the next turn. That registration is in this project's dev
|
|
154
|
+
database only. To have `kindgi dev` register it on every boot, in every
|
|
155
|
+
worktree and after `--reset`, declare it in `kindgi.config.json`:
|
|
156
|
+
`"providers": [{"preset": "anthropic"}]` (its key, `ANTHROPIC_API_KEY`, comes
|
|
157
|
+
from the env files). Details and other providers: `kindgi-authoring-providers`.
|
|
158
|
+
|
|
159
|
+
To see what Kindgi sees (the index), with no runtime:
|
|
160
|
+
|
|
161
|
+
```sh
|
|
162
|
+
./mvnw -q compile dependency:build-classpath -Dmdep.outputFile=target/classpath.txt
|
|
163
|
+
java -cp "target/classes:$(cat target/classpath.txt)" com.kindgi.pack.Main index --pack-dir .
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Flows
|
|
167
|
+
|
|
168
|
+
A flow is data: nodes and edges (`flow.schema.json`). A node's ref may be
|
|
169
|
+
the `Tool` itself:
|
|
170
|
+
|
|
171
|
+
```java
|
|
172
|
+
public static final Flow FLOW = Flow.define("acme.ledger.record-flow")
|
|
173
|
+
.version("0.1.0")
|
|
174
|
+
.toolNode("record", RecordExpense.TOOL)
|
|
175
|
+
.edge("e-start", "$start", "record")
|
|
176
|
+
.edge("e-end", "record", "$end")
|
|
177
|
+
.build();
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
A node gets the output of its single upstream node (the run input after
|
|
181
|
+
`$start`), or what its `inputMapping` says. Run one with
|
|
182
|
+
`./kindgiw runs start --flow=<id> --input='{…}'`. For branches, loops and
|
|
183
|
+
agent steps, see `kindgi-java-authoring-flows`.
|
|
184
|
+
|
|
185
|
+
## Calling Kindgi from Java
|
|
186
|
+
|
|
187
|
+
`com.kindgi:kindgi-client` (on Maven Central, at the same version as the
|
|
188
|
+
CLI) covers the whole API, with typed models and errors:
|
|
189
|
+
|
|
190
|
+
```java
|
|
191
|
+
Kindgi client = Kindgi.create(); // KINDGI_API_URL + KINDGI_API_TOKEN; in dev, the running kindgi dev
|
|
192
|
+
Run run = client.runs().start(StartRunBody.WithAgent.builder()
|
|
193
|
+
.agent("my-pack.echo-agent")
|
|
194
|
+
.input(Map.of("userMessage", "Ada"))
|
|
195
|
+
.build());
|
|
196
|
+
try (EventStream<RunEvent> events = client.runs().follow(run.id())) {
|
|
197
|
+
for (RunEvent event : events) System.out.println(event.kind());
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The methods follow the API's operations: `approvals.reviewers.list` is
|
|
202
|
+
`client.approvals().reviewers().list()`. `client.async()` has the same ones,
|
|
203
|
+
answering `CompletableFuture`s. A refused call throws a typed
|
|
204
|
+
`KindgiApiException` (`NotFoundException`, …). The client shades its own
|
|
205
|
+
Jackson, so the app's Jackson is left alone. In production it never reads
|
|
206
|
+
`.kindgirc.json`: set `KINDGI_API_URL` and `KINDGI_API_TOKEN`.
|
|
207
|
+
|
|
208
|
+
## Your app and Kindgi's data
|
|
209
|
+
|
|
210
|
+
When the app keeps something a run did (a ticket a flow triaged, an answer
|
|
211
|
+
an agent gave), its own row stores the run's id, in a column such as
|
|
212
|
+
`kindgi_run_id`. The app reads the rest through the API, server side:
|
|
213
|
+
|
|
214
|
+
- **Status, output, timing:** `client.runs().get(runId)`.
|
|
215
|
+
- **The audit, step by step:** `client.runs().journal(runId)`.
|
|
216
|
+
- **What it cost:** `client.cost().records().list(…)`, filtered by the run.
|
|
217
|
+
- **When a run finished:** the `run.finished` webhook, not polling.
|
|
218
|
+
|
|
219
|
+
Show it in the app's own UI. **Never:**
|
|
220
|
+
|
|
221
|
+
- **query Kindgi's database**, even on the app's own Postgres server, or map
|
|
222
|
+
its tables in JPA. Its schema is private and changes with every release,
|
|
223
|
+
row-level security guards every tenant query, and a runtime Kindgi hosts
|
|
224
|
+
gives no database access.
|
|
225
|
+
- **link users to Kindgi's console**, or any Kindgi UI, for this data.
|
|
226
|
+
|
|
227
|
+
Docs: https://docs.kindgi.com/v0.1/guides/runs/show-runs-in-your-app/
|
|
228
|
+
|
|
229
|
+
## Build an image
|
|
230
|
+
|
|
231
|
+
`./kindgiw build --env=<name>` builds the pack's image for an
|
|
232
|
+
`environments.<name>` block of `kindgi.config.json`; `--local` builds it with
|
|
233
|
+
this machine's Docker. Maven compiles the pack in a pinned Maven + JDK 17
|
|
234
|
+
image, fetching kindgi-pack from Maven Central. The index is built in the
|
|
235
|
+
image, and the pack service runs on a JRE 17 as its entrypoint, as user
|
|
236
|
+
65532.
|
|
237
|
+
|
|
238
|
+
Debian packages the code needs are declared in `kindgi.config.json`, and the
|
|
239
|
+
image installs them: `"image": {"systemPackages": ["tesseract-ocr"]}`
|
|
240
|
+
(names, or `name=version`). So are the variables the code reads, names only:
|
|
241
|
+
`"env": {"required": ["DATABASE_URL"], "optional": ["SENTRY_DSN"]}`. A
|
|
242
|
+
deployed pack service missing a required one isn't ready, and its `/readyz`
|
|
243
|
+
names it.
|
|
244
|
+
|
|
245
|
+
## Two things need the human
|
|
246
|
+
|
|
247
|
+
- **The pack id and version** in `kindgi.config.json`. The id prefixes every
|
|
248
|
+
primitive (`<pack-id>.<name>`): pick it once.
|
|
249
|
+
- **Model credentials.** Ask for the key; never invent or hard-code one.
|
|
250
|
+
|
|
251
|
+
## Next
|
|
252
|
+
|
|
253
|
+
- A tool: `kindgi-java-authoring-tools`.
|
|
254
|
+
- A guardrail: `kindgi-java-authoring-guardrails`.
|
|
255
|
+
- An agent: `kindgi-java-authoring-agents`.
|
|
256
|
+
- A flow: `kindgi-java-authoring-flows`.
|
|
257
|
+
- A real model: `kindgi-authoring-providers`.
|
|
258
|
+
- An external resource (a database) for the coding agent:
|
|
259
|
+
`kindgi-authoring-mcp-servers`.
|
|
260
|
+
|
|
261
|
+
## Keeping skills up to date
|
|
262
|
+
|
|
263
|
+
`./kindgiw skills sync` refreshes `.claude/skills/` from the CLI's copy
|
|
264
|
+
(local edits are kept unless `--force`). `kindgi dev` says when they are out
|
|
265
|
+
of date.
|
|
266
|
+
|
|
267
|
+
## When the framework itself is the problem
|
|
268
|
+
|
|
269
|
+
If the bug is in Kindgi or kindgi-pack and not in the pack's code, load
|
|
270
|
+
`kindgi-framework-feedback` and file it with `./kindgiw feedback write`.
|
|
@@ -15,8 +15,8 @@ description: >
|
|
|
15
15
|
model by kindgi-authoring-providers.
|
|
16
16
|
type: core
|
|
17
17
|
library: "kindgi (Python)"
|
|
18
|
-
version: "0.1.
|
|
19
|
-
sdk_version: "0.1.
|
|
18
|
+
version: "0.1.5"
|
|
19
|
+
sdk_version: "0.1.5-rc.0"
|
|
20
20
|
pack_languages: [python]
|
|
21
21
|
sources:
|
|
22
22
|
- sdks/python/src/kindgi/pack/define.py
|
|
@@ -132,9 +132,9 @@ brief_writer = Agent(
|
|
|
132
132
|
instructions.
|
|
133
133
|
- **`preferred_provider`** / **`preferred_model`** — soft hints: the
|
|
134
134
|
router prefers that provider id (e.g. `"anthropic"`) and/or model name
|
|
135
|
-
(e.g. `"claude-
|
|
135
|
+
(e.g. `"claude-sonnet-5-5"`) when they satisfy the capabilities. To
|
|
136
136
|
*require* a model, put it in the capability:
|
|
137
|
-
`{"needs": [{"feature": "tool-use"}, {"models": {"allow": ["claude-
|
|
137
|
+
`{"needs": [{"feature": "tool-use"}, {"models": {"allow": ["claude-sonnet-5-5"]}}]}`.
|
|
138
138
|
- **`conversation_policy`** — `{"historyLimit": n}` caps the prior
|
|
139
139
|
messages loaded; `hitl` configures approval gates. Absent = the full
|
|
140
140
|
history, no gates. A tenant's `hitl` policy can tighten the gates
|
|
@@ -158,7 +158,25 @@ brief_writer = Agent(
|
|
|
158
158
|
the call. Default kinds are `invalid-arguments` and `unknown-tool`
|
|
159
159
|
(nothing ran); add `tool-error` only when retrying the tool is safe.
|
|
160
160
|
Each retry costs a step.
|
|
161
|
-
- **`retrieval`** — memory
|
|
161
|
+
- **`retrieval`** — what the agent reads from memory before each turn;
|
|
162
|
+
empty = no memory. Each intent is a dict with the API's keys:
|
|
163
|
+
`{"types": ["acme.preference"], "scope": "same-user", "mode": "both",
|
|
164
|
+
"limit": 5}`. `scope` is `same-user`, `same-conversation`,
|
|
165
|
+
`same-project` or `tenant`; `mode` absent (newest first), `keyword`,
|
|
166
|
+
`semantic` or `both`. Facts reach the model as data in a `<memory>`
|
|
167
|
+
block, never as instructions. `semantic`/`both` need embeddings on the
|
|
168
|
+
runtime (`KINDGI_MEMORY_EMBEDDINGS`); without them a `semantic` intent
|
|
169
|
+
fails the turn (`semantic-unavailable`). `{"source": "conversations",
|
|
170
|
+
"scope": "same-user"}` recalls this agent's earlier conversations: the
|
|
171
|
+
people's own words only, unless `"roles": ["user", "agent"]`.
|
|
172
|
+
- **`memory`** — `{"remember": {"types": ["acme.preference"], "scope":
|
|
173
|
+
"same-user", "keepDays": 30}}` gives the turn the built-in tool
|
|
174
|
+
`kindgi_remember` (name it exactly so in the instructions). The model
|
|
175
|
+
picks type, text, `key` and expiry, never the scope; a fact wider than
|
|
176
|
+
one person, or instruction-like text, waits for a person's approval.
|
|
177
|
+
Use a model with reliable tool calling. `{"instructionTypes":
|
|
178
|
+
["acme.policy"]}` makes a retrieved, verified fact of those types an
|
|
179
|
+
instruction. See https://docs.kindgi.com/v0.1/guides/agents/give-an-agent-memory/.
|
|
162
180
|
|
|
163
181
|
## Which model answers
|
|
164
182
|
|