@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
|
-
|
|
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
|
|
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
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
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
|
-
-
|
|
943
|
-
|
|
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.
|
|
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.
|
|
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",
|