@akanjs/cli 3.0.0-beta.0 → 3.0.0-beta.2

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
- 65f8fdc9a4ad5e1054cf5bf3782626283fa2a2f9fc4e3079e0619ce0b60a4641
1
+ 91f5ad2ee63550b2ce4eee3fe99b7d2f064b37381641718bf796f2f31987b905
@@ -72,9 +72,22 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
72
72
  fills whichever adaptor holds `LlmAdaptorRole`, reaching it as the `llmOption` use. The settings are the role's
73
73
  rather than one provider's, so they survive a swap. **DeepSeek is the built-in default** (`deepseek-v4-flash` at
74
74
  `https://api.deepseek.com`); with no `apiKey` the app still boots and the chat answers `llmUnavailable`. Swap
75
- providers the way middleware is applied: `option.applyAdaptor(LlmAdaptorRole, ClaudeLlm)`, where the
76
- implementation is an `adapt()` class in a `srvkit/` implementing `LlmAdaptor.chat(request, onDelta?)` — ignore
77
- `onDelta` and the chat still answers whole.
75
+ providers the way middleware is applied: `option.applyAdaptor(LlmAdaptorRole, AnthropicLlm)`. An app may still
76
+ write its own — an `adapt()` class in a `srvkit/` implementing `LlmAdaptor.chat(request, onDelta?)`, where
77
+ ignoring `onDelta` still answers whole — but for vision it no longer has to.
78
+ - **Three providers ship, and only two of them read a picture.** `DeepseekLlm` is the default and declares no
79
+ `accepts`, which is a fact about its API rather than a gap. `OpenaiLlm` speaks the same chat-completions dialect
80
+ — `OpenaiDialect`, shared between them so a protocol fix lands once — against `https://api.openai.com/v1` and
81
+ declares `{ image: true }`, sending an image as a content part. `AnthropicLlm` is the Messages API and declares
82
+ `{ image: true, document: true }`; it is its own file rather than a branch, because the system prompt is a field
83
+ and not a message, tool calls and results are content blocks, the results ride in a *user* turn, roles must
84
+ alternate — so two wire turns that map to one role are merged — and `max_tokens` is required. **Both new ones
85
+ require `model`**: a default would age into a 404, and worse, it would decide the vision claim for the app.
86
+ - **`accepts` is answered per model, through `option.setLlm({ accepts })`.** An adaptor answers for an API and one
87
+ API serves models that differ, so the override rides beside the `model` it is a fact about. It is not a table
88
+ the framework keeps: a table is a claim about models that ship after it, and getting this wrong is the worst
89
+ failure available — a provider handed bytes it cannot decode either refuses the turn or accepts it having seen
90
+ nothing, and the model then answers confidently about a file it never read.
78
91
  - **An adaptor answers `null` for "not configured" and *throws* for a refusal it can explain.** The two are
79
92
  different things to be told: collapsing both into `null`, the way the adapter convention otherwise reads, left a
80
93
  user reading `llmUnavailable` — "no model is configured" — about a conversation that had merely outgrown the
@@ -92,8 +105,11 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
92
105
  prompt. **What the provider cannot read is replaced by a note naming the file**, never dropped: an attachment the
93
106
  model never saw is one it answers about from the filename. An adaptor declares `accepts: { image, document }` and
94
107
  `AgentService.readable` degrades the rest, so a text-only provider needs no attachment code at all — DeepSeek
95
- declares none, which is why an image against the default provider is refused out loud while an extracted PDF
96
- works, `text` being readable by every model there is. Persisting keeps each
108
+ declares none, which is why an image against the *default* provider is refused out loud while an extracted PDF
109
+ works, `text` being readable by every model there is. Swap in `OpenaiLlm` or `AnthropicLlm` and the same image
110
+ arrives as an image. `accepts.document` is one boolean over every non-image type, so an adaptor whose API has a
111
+ block for only some of them — Anthropic's `document` is PDF and nothing else — names the rest in the text rather
112
+ than dropping them, which is the wire's own rule applied at the one layer that knows which blocks exist. Persisting keeps each
97
113
  attachment's name and drops its content: web storage is a few megabytes, one screenshot fills a chunk of it, and
98
114
  a save that fails is silent — so keeping the bytes would quietly stop keeping the transcript.
99
115
  **The ceilings are the message's, not the file's**: 4 MB per file, 8 MB and five files per message, and the same
@@ -696,7 +696,9 @@ what every developer must know even when not building one.
696
696
  every tool runs in the caller's own browser session, gated by guards and the approval card. Its guard is
697
697
  `AgentRelayAccess`, which refuses every call until the app names a guard of its own —
698
698
  `option.setAgentAccess(SignedIn)`. **The LLM is configured in `option.ts`, never through the environment**
699
- (`option.setLlm({ apiKey, model, host })`).
699
+ (`option.setLlm({ apiKey, model, host })`). Three providers ship — `DeepseekLlm` (the default, text only),
700
+ `OpenaiLlm` and `AnthropicLlm` (both read images) — and swapping one in is
701
+ `option.applyAdaptor(LlmAdaptorRole, AnthropicLlm)`.
700
702
  - **Declare the tool beside the control that already does it**, never as a separate surface:
701
703
  `st.tool("x").desc("…").arg("id", ID).exec(fn)` returns the callable to hand to `onClick` — one handler for the
702
704
  person and the agent. Publish it only where the screen already renders the control; a falsy name declares the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/cli",
3
- "version": "3.0.0-beta.0",
3
+ "version": "3.0.0-beta.2",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -33,7 +33,7 @@
33
33
  "@langchain/openai": "^1.4.6",
34
34
  "@tailwindcss/node": "^4.3.0",
35
35
  "@trapezedev/project": "^7.1.4",
36
- "akanjs": "3.0.0-beta.0",
36
+ "akanjs": "3.0.0-beta.2",
37
37
  "chalk": "^5.6.2",
38
38
  "commander": "^14.0.3",
39
39
  "dayjs": "^1.11.20",