# Kotlin functions that answer questions about text

A `KotlinFacade` over the Java door. Its calls take strings.

## Install

| Channel | Note |
| --- | --- |
| `io.github.botassembly:thinkthen-jvm:VERSION:kotlin` | The Kotlin JAR. Add the Java coordinate beside it. |
| `thinkthen-jvm-VERSION-TARGET.tar.gz` | The door, Kotlin and Scala JARs, from each release. |
| `thinkthen-c-VERSION-TARGET.tar.gz` | The C library it calls, from the same release. |

Set `THINKTHEN_API_KEY` in the environment.

## A first call

```
import thinkthen.Door
import thinkthen.Door.Outcome

fun main() {
    Door().use { engine ->
        val tt = KotlinFacade(engine)
        val question =
            "Does the customer ask for a refund?"
        var isRefund = tt.decide(
            question,
            "Please refund my order. It arrived broken.",
        )
        check(Door.outcome(isRefund.value()) == Outcome.YES)

        val refund = """
            {"decide": "$question",
             "threshold": "0.2:0.8"}
        """.trimIndent()
        isRefund = tt.decide(
            refund,
            "I want to send this back.",
        )
        val outcome = Door.outcome(isRefund.value())
        check(outcome == Outcome.NOT_SURE)
    }
}
```

*Build and run it beside the unpacked archives, thinkthen-c/ and thinkthen-jvm/*

```
kotlinc -jvm-target 21 \
    -cp thinkthen-jvm/thinkthen-door.jar:thinkthen-jvm/thinkthen-kotlin.jar \
    FirstCall.kt -include-runtime -d FirstCall.jar
java --enable-preview -ea \
    --enable-native-access=ALL-UNNAMED \
    -Dthinkthen.library="$PWD/thinkthen-c/lib/libthinkthen.so" \
    -cp thinkthen-jvm/thinkthen-door.jar:thinkthen-jvm/thinkthen-kotlin.jar:FirstCall.jar \
    FirstCallKt
```

Not sure comes back as `Outcome.NOT_SURE`. Branch on it and send those cases to a person.

## Run facts

`decide` returns the door's `TypedResult`. `value()` holds the answer, and `facts()` holds this call's run facts as a `Map`.

## Errors

A failed call throws a `Door.NativeFailure`, as in Java. Its `failure` names the kind, the message and the retry flag.

## Settings and recording

`Door(settingsJson)` takes the settings as JSON. `"record"` writes a recording to a folder. `"replay"` answers from that recording with no connection. The [Settings](/install/settings/) page lists every setting.

## Jev, Liquid d1 and Ollama from Kotlin

Kotlin reads its backend from the environment. Set `THINKTHEN_BACKEND` to the name below. Set the backend's key variable in the shell, and the same sample asks that backend.

| Backend | Name | Key variable |
| --- | --- | --- |
| [TypeSafe Jev](/install/backends/typesafe/) | `typesafe` | `TYPESAFE_API_KEY` |
| [Liquid d1](/install/backends/liquid/) | `liquid` | `LIQUIDAI_API_KEY`, then `LIQUID_API_KEY` |
| [Ollama](/install/backends/ollama/) | `ollama` | `OLLAMA_API_KEY`. A local address needs no key. |

*Ask TypeSafe Jev.*

```
export THINKTHEN_BACKEND=typesafe
export TYPESAFE_API_KEY=...
```

*Ask Liquid d1.*

```
export THINKTHEN_BACKEND=liquid
export LIQUIDAI_API_KEY=...
```

*Ask Ollama. This block names a second port, 11535, as the site's runs do. On the default port, leave THINKTHEN_BASE_URL out.*

```
export THINKTHEN_BACKEND=ollama
export THINKTHEN_BASE_URL=http://localhost:11535/v1
```

```
import thinkthen.Door
import thinkthen.Door.Outcome

fun main() {
    Door().use { engine ->
        val tt = KotlinFacade(engine)
        val question =
            "Does the customer ask for a refund?"
        val brokenIsRefund = tt.decide(
            question,
            "Please refund my order. It arrived broken.",
        )
        val thanksIsRefund = tt.decide(
            question,
            "Thanks for the quick help yesterday!",
        )
        val broken = Door.outcome(brokenIsRefund.value())
        val thanks = Door.outcome(thanksIsRefund.value())
        check(broken == Outcome.YES)
        check(thanks == Outcome.NO)
    }
}
```

*Build and run it beside the unpacked archives, thinkthen-c/ and thinkthen-jvm/*

```
kotlinc -jvm-target 21 \
    -cp thinkthen-jvm/thinkthen-door.jar:thinkthen-jvm/thinkthen-kotlin.jar \
    Backends.kt -include-runtime -d Backends.jar
java --enable-preview -ea \
    --enable-native-access=ALL-UNNAMED \
    -Dthinkthen.library="$PWD/thinkthen-c/lib/libthinkthen.so" \
    -cp thinkthen-jvm/thinkthen-door.jar:thinkthen-jvm/thinkthen-kotlin.jar:Backends.jar \
    BackendsKt
```

The configuration file's `backend` names a default backend for every run. The [Configuration](/install/configuration/#configuration-file) page shows the file.

### OpenAI Decisions API from Kotlin

OpenAI announced its Decisions API on 2026-09-29 in its [DevDay 2026 recap](https://openai.com/index/devday-2026-recap/). OpenAI has published no address, schema or price, so ThinkThen cannot call it. The [OpenAI Decisions API](/install/backends/openai/) page says what ThinkThen knows.

## What is different in Kotlin

- `decideAsync` runs a call on its own thread. `await()` gives the answer. Close it before the door.
- The run takes the same `java` flags as Java: `--enable-preview` and `-Dthinkthen.library`.

On GitHub: [github.com/botassembly/thinkthen](https://github.com/botassembly/thinkthen)
