@akanjs/cli 3.0.0-alpha.42 → 3.0.0-alpha.43

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/.build-stamp CHANGED
@@ -1 +1 @@
1
- eaeb44245969a1707e38a765624a1541652e2558214acaf1d91d2be618ba8bbe
1
+ d8a476b01467d4b59495cc5a6332930a9ce6ba7001dd3a4bf3510bf13d6cd839
@@ -680,7 +680,11 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
680
680
  guard classes every endpoint takes (an array is ANDed, `null` clears what a library set); without one the chat
681
681
  cannot spend the LLM key.
682
682
  `persist` keeps the transcript across reloads (sessionStorage; `{ storage: "local" }` to outlive the tab),
683
- default off. Re-skin through the `AgentChat` slot in `_overrides.tsx`.
683
+ default off, and `shortcut={false}` gives the browser back the Cmd/Ctrl+L the launcher otherwise captures.
684
+ **A session the chat made ends when the chat unmounts** — nothing renders its approvals once it is gone, so a
685
+ turn left running would drive a screen the user has navigated away from; a session handed down by an
686
+ `AgentProvider` or an `Agent.Zone` belongs to whoever provided it. Re-skin through the `AgentChat` slot in
687
+ `_overrides.tsx`.
684
688
  - **The LLM is configured in `option.ts`, never through the environment.** `option.setLlm({ apiKey, model, host })`
685
689
  — or `setLlm((options) => …)` to read the key out of the app's own env object, which is where a secret belongs —
686
690
  fills whichever adaptor holds `LlmAdaptorRole`, reaching it as the `llmOption` use. The settings are the role's
@@ -709,12 +713,18 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
709
713
  reaches the chat as an attachment rather than the literal `[image]` it used to become. Persisting keeps each
710
714
  attachment's name and drops its content: web storage is a few megabytes, one screenshot fills a chunk of it, and
711
715
  a save that fails is silent — so keeping the bytes would quietly stop keeping the transcript.
716
+ **The ceilings are the message's, not the file's**: 4 MB per file, 8 MB and five files per message, and the same
717
+ file twice is refused by name. The bytes ride inside one turn's JSON, so what a provider refuses is the sum —
718
+ and a request that cannot be sent is one the user has to empty the composer to escape, which is why the refusal
719
+ happens at the paperclip and names the file it dropped.
712
720
  - **Speech is one engine contract and the framework's own policy.** `<Agent.Chat voice={engine} />` takes a
713
721
  `VoiceEngine` — `listen(handlers)` and `speak(sentence)`, both cancellable — and the chat decides everything
714
722
  else: a press-to-talk microphone whose transcript lands in the composer to be corrected, one utterance per
715
723
  press, sentence-at-a-time reading, barge-in on the next press or on Stop, and markdown stripped so `**bold**`
716
724
  is not pronounced. **A reply is read aloud only when the ask arrived by voice**, so a typed question never turns
717
725
  on the speakers — and it needs no wire field, because how a message was sent is the composer's own business.
726
+ A question or an approval the loop parked on is read aloud under that same condition, because the loop stops
727
+ there: a voice user who is never told about the card is a conversation that simply ends.
718
728
  The contract is a subscription rather than `listen(): Promise<string>` on purpose: a promise fits push-to-talk
719
729
  and nothing else, so hands-free could then only arrive as a breaking change. `useSpeech` in
720
730
  `libs/util/webkit` is the engine — the browser's own recognition and synthesis on the web, the Capacitor
@@ -903,17 +913,20 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
903
913
  read unless a `mask:` model is named — the same rule and wording as `AgentBridge.read`.
904
914
  - **`prompt()` endpoints double as the chat's slash commands.** There is no listing endpoint — the client reads
905
915
  its own serialized signals — so a prompt's dictionary `.desc()` is what the menu shows, and its guards are
906
- enforced by the prompt's own GET at call time.
916
+ enforced by the prompt's own GET at call time. Arguments are positional and whitespace-separated, and quoting
917
+ is how a sentence stays one of them (`/reviewTask t1 "look at the totals"`) — a prompt taking a single `String`
918
+ is the common case, and an unquoted sentence would fill its second parameter with the second word.
907
919
  - **The chat answers six slash commands of its own**, listed in the same `/` menu ahead of the prompts:
908
920
  `/new` (`/clear`), `/retry`, `/compact`, `/copy`, `/help` and `/tools`. An app writes none of them and cannot add
909
921
  one — the extension point for a product's own command is a `prompt()` endpoint, which is guarded and server-side.
910
922
  **A built-in wins a name collision with a prompt of the same name**, the mirror image of the tool rule: a
911
923
  component's `st.tool` shadows a built-in it means to replace, but no library's prompt may take `/new` away from
912
924
  the user who typed it — so a shadowed prompt is dropped from the menu rather than listed twice. `/new` and
913
- `/copy` are also dispatched *before* the is-a-turn-running check, because mid-turn is exactly when they are
914
- reached for; `/new` therefore aborts the turn it is clearing and waits for it to wind down, since the loop
915
- clears its own running flag a microtask later and a transcript emptied before that lands is one the dying turn
916
- appends onto.
925
+ `/copy` are also dispatched *before* the is-a-turn-running check **and before the question card takes the
926
+ composer**, because mid-turn is exactly when they are reached for and a question the agent asked is the middle
927
+ of a turn like any other answered as text, `/new` would have reached the model as the user's decision.
928
+ `/new` therefore aborts the turn it is clearing and waits for it to wind down, since the loop clears its own
929
+ running flag a microtask later and a transcript emptied before that lands is one the dying turn appends onto.
917
930
  - **A command's output is a `local` message: rendered in the transcript, withheld from the wire.** The transcript
918
931
  *is* the model's history, so `/help` text appended plainly would come back next turn as something the assistant
919
932
  believes it said. `session.note(text)` is the only way to write one, `session.report(error)` stays what a
@@ -939,8 +952,22 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
939
952
  have; one that fails to shrink anything is not retried until another threshold's worth has been added. On the
940
953
  wire a summary wears the user's role because the wire has no other, so a provider mapping frames it as a system
941
954
  message and `/retry` steps over it — replaying it would send the notes back as a question.
942
- - **↑ and in the composer walk what was sent.** A single-line input has nothing of its own on the vertical
943
- arrows, and the half-written draft they were walked away from comes back at the bottom of the walk.
955
+ - **A stopped turn answers the calls it never ran, because an unanswered call ends the conversation.** Every
956
+ provider dialect refuses an assistant message whose `tool_calls` have no results on that turn and on every
957
+ later one — so Stop landing between a call and its result would leave a transcript nothing can be sent from,
958
+ with no way out but `/new`. `Transcript.sanitize` holds the invariant in one place and runs where a transcript
959
+ is assembled rather than where each hole is made: the turn's own request, a transcript restored from storage,
960
+ and a stored transcript capped to its newest messages, whose window can start mid-pair. A call the loop never
961
+ reached is *answered* rather than erased — a model told the call was stopped asks again, where one shown no
962
+ call at all answers as if it had the result.
963
+ - **A turn that failed says so on the wire.** `error` is a field only this wire has, so a provider mapping reads
964
+ `text` and drops it; `AgentService.explained` folds it into the text before any adaptor sees it, because an
965
+ assistant turn that says nothing is one the model repeats.
966
+ - **↑ and ↓ in the composer walk what was sent**, seeded from the transcript so a persisted chat does not lose
967
+ only what was just typed. A single-line input has nothing of its own on the vertical arrows, and the
968
+ half-written draft they were walked away from comes back at the bottom of the walk. **The `/` menu takes those
969
+ keys while it is open** — it is the thing on screen the arrows point at — with Enter picking the highlighted
970
+ row, Tab completing its name, and Escape closing the menu and then, pressed again, the panel.
944
971
  - The framework publishes six built-ins on every store surface: `navigate` (internal paths only, the same
945
972
  router `Link` rides), `goBack` (this session's history — global, because history is not a control a page owns and
946
973
  a page that draws no back link is not one you may not leave), `readScreen` (the rendered DOM as compact text —
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/cli",
3
- "version": "3.0.0-alpha.42",
3
+ "version": "3.0.0-alpha.43",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -34,7 +34,7 @@
34
34
  "@langchain/openai": "^1.4.6",
35
35
  "@tailwindcss/node": "^4.3.0",
36
36
  "@trapezedev/project": "^7.1.4",
37
- "akanjs": "3.0.0-alpha.42",
37
+ "akanjs": "3.0.0-alpha.43",
38
38
  "chalk": "^5.6.2",
39
39
  "commander": "^14.0.3",
40
40
  "dayjs": "^1.11.20",