# @jpfi/stories ## Intent This package lets a parent ask a Kody host for a Teddy & Pinguin bedtime story and get the finished German or English text back. Success is readable prose plus a link to the story in their own Teddy library. Each caller connects their own Teddy & Pinguin account with a personal access token stored in Kody as `teddyPinguinToken`. Stories are created in that account and count against that account's story quota. ## Setup 1. Create an account at https://www.teddy-pinguin.com and verify your email. 2. Open **API tokens** (`/de/account/api-tokens`) and create a token labeled `Kody`. 3. Save it in Kody at `/account/secrets/new?name=teddyPinguinToken&allowedHosts=www.teddy-pinguin.com`. Never paste the token into a chat. 4. Approve `www.teddy-pinguin.com` as an outbound host for the secret. 5. Confirm with `check-connection` before your first story. ## Exports | Export | Purpose | | --- | --- | | `check-connection` | Verify the stored token reaches a Teddy account. Read-only, no quota cost. | | `generate-story` | Create a story from an idea and wait for the finished prose. Optional `series` or `continueFromStoryId` writes the next episode. | | `get-story-result` | Pick up a story that was still being written when `generate-story` returned. | Every export returns a tagged result. It never throws for an expected condition. Branch on `status`. | `status` | What happened | What to do | | --- | --- | --- | | `ready` | Accepted prose is in `story` | Read it aloud. Link `story.libraryUrl`. | | `pending` | Still being written. The run continues server-side. | Say `nextStep`. Call `get-story-result` later. | | `declined` | Teddy's Reviewer said no, or the run was cancelled. | Offer to rephrase if `canRetry`. | | `unavailable` | Quota used up, rate limited, or generation failed. | Wait `retryAfterSeconds`, or check the account. | | `disconnected` | The token is missing, revoked, or expired. | Send the human to `tokenSetupUrl`. | | `invalid_input` | `storyIdea` or `runId` is unusable. | Fix `field` and call again. | ## Same request for 30 minutes If you already have a `runId` from a `pending` result, call `get-story-result`. Do not call `generate-story` again for that request. If the host lost the `runId` and submits the same `storyIdea`, `contentLocale`, and `targetReadMinutes` within 30 minutes, Teddy reattaches to the run already in flight. The Idempotency-Key is derived from those fields plus optional series identity, the API origin, and a 30-minute time bucket. It is unique per Teddy user, so two parents with the same idea do not collide. To get a different story, change the idea. After 30 minutes the same words produce a new story. ## Length, locale, and wait - `contentLocale` defaults to `"de"`. - `targetReadMinutes` defaults to `8` and is clamped into Teddy's supported 5–12 range. - `maxWaitSeconds` defaults to `300` and is capped at `360`. A story that is still unfinished when the budget runs out returns `pending` with a `runId`. `maxWaitSeconds: 0` performs exactly one status check. ## Optional preview override Set package storage key `apiBaseUrl` to an `https://` origin to point at a Vercel preview deployment. The `teddyPinguinToken` secret must also list that host under its allowed hosts. Production default is `https://www.teddy-pinguin.com`. ## Name Published as `@jpfi/stories`. Canonical source is `integrations/kody-stories/` in the teddy-pinguin repository.