akanjs 3.0.0-beta.13 → 3.0.0-beta.15
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/common/CodeAgentClient.ts +102 -0
- package/common/CodeTranscript.ts +337 -0
- package/common/codeAgentProfile.ts +175 -0
- package/common/codeAgentWire.ts +409 -0
- package/common/index.ts +51 -0
- package/common/markdownSpans.ts +57 -0
- package/dictionary/agent.dictionary.ts +4 -11
- package/dictionary/base.dictionary.ts +1 -0
- package/local/apps/serverLifecycle/serverLifecycle-local.db-shm +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-shm +0 -0
- package/package.json +3 -1
- package/server/akanOption.ts +9 -2
- package/server/di/predefinedAdaptor.ts +2 -2
- package/service/predefinedAdaptor/anthropicLlm.ts +6 -4
- package/service/predefinedAdaptor/index.ts +0 -1
- package/service/predefinedAdaptor/llm.adaptor.ts +21 -1
- package/service/predefinedAdaptor/openaiLlm.ts +37 -18
- package/store/agentic/StToolBuilder.ts +54 -0
- package/store/agentic/attachAgentic.ts +2 -1
- package/store/agentic/useFormTools.ts +1 -1
- package/types/common/CodeAgentClient.d.ts +26 -0
- package/types/common/CodeTranscript.d.ts +99 -0
- package/types/common/codeAgentProfile.d.ts +111 -0
- package/types/common/codeAgentWire.d.ts +388 -0
- package/types/common/index.d.ts +7 -0
- package/types/common/markdownSpans.d.ts +40 -0
- package/types/dictionary/agent.dictionary.d.ts +1 -1
- package/types/dictionary/base.dictionary.d.ts +1 -1
- package/types/dictionary/dictionary.d.ts +9 -9
- package/types/server/akanOption.d.ts +9 -2
- package/types/server/di/predefinedAdaptor.d.ts +2 -2
- package/types/service/predefinedAdaptor/anthropicLlm.d.ts +1 -1
- package/types/service/predefinedAdaptor/index.d.ts +0 -1
- package/types/service/predefinedAdaptor/llm.adaptor.d.ts +14 -1
- package/types/service/predefinedAdaptor/openaiLlm.d.ts +20 -11
- package/types/store/agentic/StToolBuilder.d.ts +22 -0
- package/types/store/agentic/attachAgentic.d.ts +2 -1
- package/types/store/baseSt.d.ts +2 -2
- package/types/ui/Agent/Chat.d.ts +7 -1
- package/types/ui/Agent/Composer.d.ts +17 -1
- package/types/ui/Agent/MentionNode.d.ts +26 -0
- package/types/ui/Agent/RichInput.d.ts +22 -0
- package/types/ui/Agent/ToolCard.d.ts +16 -0
- package/types/ui/Agent/markdownSpans.d.ts +1 -0
- package/types/ui/Agent/mentionDraft.d.ts +19 -0
- package/types/ui/Agent/useChatReferences.d.ts +3 -2
- package/types/ui/UiOverride/context.d.ts +2 -0
- package/types/ui/index.d.ts +2 -1
- package/types/ui/recipe/badgeRecipe.d.ts +2 -2
- package/types/ui/recipe/buttonRecipe.d.ts +2 -2
- package/types/vendor/use-agentic/AgentSession.d.ts +15 -1
- package/types/vendor/use-agentic/ToolRunner.d.ts +21 -1
- package/types/vendor/use-agentic/types.d.ts +31 -1
- package/ui/Agent/Chat.tsx +24 -7
- package/ui/Agent/Composer.tsx +73 -21
- package/ui/Agent/Markdown.tsx +2 -2
- package/ui/Agent/MentionNode.ts +62 -0
- package/ui/Agent/RichInput.tsx +154 -0
- package/ui/Agent/ToolCard.tsx +39 -0
- package/ui/Agent/markdownSpans.tsx +26 -36
- package/ui/Agent/mentionDraft.ts +101 -0
- package/ui/Agent/useChatReferences.ts +5 -8
- package/ui/UiOverride/context.ts +2 -0
- package/ui/index.ts +2 -1
- package/vendor/use-agentic/AgentSession.ts +45 -1
- package/vendor/use-agentic/AgenticSurface.ts +2 -0
- package/vendor/use-agentic/ToolRunner.ts +55 -1
- package/vendor/use-agentic/types.ts +36 -1
- package/service/predefinedAdaptor/deepseekLlm.ts +0 -82
- package/types/service/predefinedAdaptor/deepseekLlm.d.ts +0 -19
- /package/{ui/Agent → common}/markdownBlocks.ts +0 -0
- /package/{ui/Agent → common}/markdownTable.ts +0 -0
- /package/types/{ui/Agent → common}/markdownBlocks.d.ts +0 -0
- /package/types/{ui/Agent → common}/markdownTable.d.ts +0 -0
|
@@ -38,8 +38,15 @@ export declare class AkanOption<Env extends BackendEnv = BackendEnv> {
|
|
|
38
38
|
* itself is on by default and `{ enabled: false }` is for an API no browser reaches.
|
|
39
39
|
*/
|
|
40
40
|
setCrossSite(crossSite: CrossSiteOption): this;
|
|
41
|
-
/**
|
|
42
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Settings for whichever adaptor fills `LlmAdaptorRole`, injected into it as the `llmOption` use.
|
|
43
|
+
*
|
|
44
|
+
* The argument is generic so that whatever an adaptor needs beyond `LlmOption` travels here too: an adaptor an
|
|
45
|
+
* app or a library wrote declares its own interface extending it, reads it with `use<MyLlmOption>()`, and its
|
|
46
|
+
* region or project id rides the same channel the shipped fields do. Entries merge in mount order with the
|
|
47
|
+
* app's last, so a library may name a host and the app the key.
|
|
48
|
+
*/
|
|
49
|
+
setLlm<Option extends LlmOption>(llmOrFn: Option | ((env: Env) => Option)): this;
|
|
43
50
|
/** Every entry in declaration order, duplicates kept: the boot stage rejects a key claimed twice. */
|
|
44
51
|
getUses(env: Env): [string, PromiseOrObject<unknown>][];
|
|
45
52
|
getMiddlewares(): MiddlewareCls[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DatabaseMode } from "akanjs";
|
|
2
|
-
import { type AdaptorCls, BlobStorage, type CacheAdaptor, type CompressAdaptor, ConsoleLogger, type DatabaseAdaptor,
|
|
2
|
+
import { type AdaptorCls, BlobStorage, type CacheAdaptor, type CompressAdaptor, ConsoleLogger, type DatabaseAdaptor, JsonCompressor, type LlmAdaptor, type LoggingAdaptor, OpenaiLlm, type QueueAdaptor, type ScheduleAdaptor, Scheduler, SolidCache, SolidPubSub, SolidQueue, SqliteDatabase, type StorageAdaptor, type WebsocketAdaptor } from "akanjs/service";
|
|
3
3
|
export interface PredefinedAdaptor {
|
|
4
4
|
database: AdaptorCls<DatabaseAdaptor>;
|
|
5
5
|
cache: AdaptorCls<CacheAdaptor>;
|
|
@@ -31,6 +31,6 @@ export declare const predefinedAdaptor: {
|
|
|
31
31
|
logging: typeof ConsoleLogger;
|
|
32
32
|
websocket: typeof SolidPubSub;
|
|
33
33
|
compress: typeof JsonCompressor;
|
|
34
|
-
llm: typeof
|
|
34
|
+
llm: typeof OpenaiLlm;
|
|
35
35
|
};
|
|
36
36
|
export declare const getPredefinedAdaptor: (mode?: DatabaseMode) => PredefinedAdaptor;
|
|
@@ -78,7 +78,7 @@ export declare class AnthropicLlm extends AnthropicLlm_base implements LlmAdapto
|
|
|
78
78
|
/** What the API's blocks carry. A model of the family that reads neither takes the `accepts` override. */
|
|
79
79
|
get accepts(): LlmAccepts;
|
|
80
80
|
chat(request: LlmTurnRequest, onDelta?: (delta: string) => void): Promise<LlmTurnAnswer | null>;
|
|
81
|
-
static refusal(response: Response): Promise<Error>;
|
|
81
|
+
static refusal(host: string, response: Response): Promise<Error>;
|
|
82
82
|
/** The API answers a refusal as `{ error: { type, message } }`, and the sentence is the half worth printing. */
|
|
83
83
|
static reasonOf(response: Response): Promise<string>;
|
|
84
84
|
static requestBody(model: string, request: LlmTurnRequest, { accepts, stream, maxTokens }?: {
|
|
@@ -2,7 +2,6 @@ export * from "./anthropicLlm.d.ts";
|
|
|
2
2
|
export * from "./cache.adaptor";
|
|
3
3
|
export * from "./compress.adaptor";
|
|
4
4
|
export * from "./database.adaptor";
|
|
5
|
-
export * from "./deepseekLlm.d.ts";
|
|
6
5
|
export * from "./insightQuery.d.ts";
|
|
7
6
|
export * from "./llm.adaptor";
|
|
8
7
|
export * from "./logging.adaptor";
|
|
@@ -120,7 +120,12 @@ export interface LlmAccepts {
|
|
|
120
120
|
/**
|
|
121
121
|
* Settings for whichever adaptor fills `LlmAdaptorRole`, registered with `option.setLlm(...)` and injected as the
|
|
122
122
|
* `llmOption` use. It belongs to the role rather than to one provider: swapping the default for another `adapt()`
|
|
123
|
-
* class re-reads the same
|
|
123
|
+
* class re-reads the same fields under that provider's own defaults.
|
|
124
|
+
*
|
|
125
|
+
* It is the floor, not the whole shape. `setLlm` keeps whatever else it is handed, so an adaptor an app or a
|
|
126
|
+
* library wrote declares its own interface extending this one and reads it with `use<MyLlmOption>()` — a region,
|
|
127
|
+
* a project id, a deployment name reach it through the same channel the fields below do, instead of a second
|
|
128
|
+
* `option.use({...})` key beside it.
|
|
124
129
|
*/
|
|
125
130
|
export interface LlmOption {
|
|
126
131
|
apiKey?: string;
|
|
@@ -145,3 +150,11 @@ export interface LlmOption {
|
|
|
145
150
|
*/
|
|
146
151
|
maxTokens?: number;
|
|
147
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* What the chat prints as the party that refused a turn, carried on `agent.error.llmRequestFailed`.
|
|
155
|
+
*
|
|
156
|
+
* It is the host rather than the adaptor's own name because one adaptor speaks one dialect to whatever host it
|
|
157
|
+
* is pointed at — an OpenAI-dialect class aimed at a gateway would otherwise credit OpenAI for that gateway's
|
|
158
|
+
* refusal. A host that is not a URL is printed as written; there is nothing better to say about it.
|
|
159
|
+
*/
|
|
160
|
+
export declare const llmProviderOf: (host: string) => string;
|
|
@@ -1,24 +1,33 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type LlmAccepts, type LlmAdaptor, type LlmOption, type LlmTurnAnswer, type LlmTurnRequest } from "./llm.adaptor";
|
|
2
2
|
declare const OpenaiLlm_base: import("..").AdaptorCls<{}, {
|
|
3
3
|
llmOption: import("..").InjectInfo<"use", LlmOption, never, never>;
|
|
4
4
|
}>;
|
|
5
5
|
/**
|
|
6
|
-
* OpenAI
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* The OpenAI chat-completions dialect, pointed at a host — and the framework's default fill for `LlmAdaptorRole`.
|
|
7
|
+
*
|
|
8
|
+
* One class rather than one per vendor: DeepSeek, Groq, Together, OpenRouter, Ollama and a self-hosted vLLM all
|
|
9
|
+
* serve this same wire, so what distinguishes them is `option.setLlm({ host, model })` and not a protocol. A
|
|
10
|
+
* provider that speaks its own wire — Anthropic's blocks, Bedrock's signed requests — is a different adaptor
|
|
11
|
+
* class, in this package or in the app's own `srvkit/`, applied with
|
|
12
|
+
* `option.applyAdaptor(LlmAdaptorRole, TheClass)`.
|
|
10
13
|
*
|
|
11
14
|
* `model` is required and has no default. A default would be a model name that ages out of the provider's
|
|
12
|
-
* catalogue into a 404 at the first turn, and — worse
|
|
13
|
-
*
|
|
14
|
-
* `accepts: { image: false }` beside it when that model is one of the provider's text-only ones.
|
|
15
|
+
* catalogue into a 404 at the first turn, and — worse — it would decide the vision claim below on the app's
|
|
16
|
+
* behalf.
|
|
15
17
|
*/
|
|
16
18
|
export declare class OpenaiLlm extends OpenaiLlm_base implements LlmAdaptor {
|
|
17
19
|
#private;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
static readonly defaultHost = "https://api.openai.com/v1";
|
|
21
|
+
/**
|
|
22
|
+
* OpenAI's own endpoint takes image parts, so that is what is claimed for the default host. A host the app
|
|
23
|
+
* named is a gateway this class knows nothing about, and claiming vision for one is the worst guess available:
|
|
24
|
+
* the bytes reach a model that cannot decode them and the whole turn dies on a 400, where text-only degrades
|
|
25
|
+
* them to a note the model can repeat back. So a named host is text-only until `option.setLlm({ accepts })`
|
|
26
|
+
* says otherwise — as is the OpenAI model that reads no image.
|
|
27
|
+
*/
|
|
28
|
+
get accepts(): LlmAccepts | undefined;
|
|
20
29
|
chat(request: LlmTurnRequest, onDelta?: (delta: string) => void): Promise<LlmTurnAnswer | null>;
|
|
21
30
|
/** Carried on the `Err` so the chat prints the provider's own sentence rather than a status number. */
|
|
22
|
-
static refusal(response: Response): Promise<Error>;
|
|
31
|
+
static refusal(host: string, response: Response): Promise<Error>;
|
|
23
32
|
}
|
|
24
33
|
export {};
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { type CLIENT_VALUE, type EnumInstance } from "akanjs/base";
|
|
2
2
|
import type { ParamFieldType } from "akanjs/constant";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
3
4
|
import { type JsonSchema, type ToolConfirm, type ToolGuard } from "../../vendor/use-agentic.d.ts";
|
|
5
|
+
/**
|
|
6
|
+
* The two ways a card ends the call it is parked on. `submit`'s value is what the model reads back, `cancel` is
|
|
7
|
+
* why there is none; the first one settles it and the card leaves the screen.
|
|
8
|
+
*/
|
|
9
|
+
export interface StToolCardControl {
|
|
10
|
+
submit: (value: unknown) => void;
|
|
11
|
+
cancel: (reason?: string) => void;
|
|
12
|
+
}
|
|
4
13
|
export interface StToolMeta {
|
|
5
14
|
/**
|
|
6
15
|
* Whether the call has to be waited out before what it did to the screen is reported back to the model. `false`
|
|
@@ -66,6 +75,19 @@ export declare class StToolBuilder<Args extends unknown[] = []> {
|
|
|
66
75
|
* no longer offers.
|
|
67
76
|
*/
|
|
68
77
|
exec(run: (...args: Args) => unknown): (...args: Args) => Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* The other way a chain ends, for a tool whose answer belongs to the **user**: the call parks in the chat, the
|
|
80
|
+
* card renders there, and what it submits is what the model reads back. `.exec()` runs a function; this one runs
|
|
81
|
+
* a person, which is the whole difference — a name and a phone number are theirs to type, and a model that
|
|
82
|
+
* invents them has answered its own question.
|
|
83
|
+
*
|
|
84
|
+
* The arguments arrive positional like `.exec()`'s, and they are checked **before** the card is parked rather
|
|
85
|
+
* than while it renders: a bad argument has to reach the model as a refusal it can correct, and a throw inside
|
|
86
|
+
* the render would take the chat panel down with it instead.
|
|
87
|
+
*
|
|
88
|
+
* `confirm` is not read here. The card in front of the user is already the asking.
|
|
89
|
+
*/
|
|
90
|
+
card(render: (control: StToolCardControl, ...args: Args) => ReactNode): void;
|
|
69
91
|
static parametersOf(args: StToolArg[]): JsonSchema | undefined;
|
|
70
92
|
/** Scalars and enums only — the value arrives as JSON from a model, so a class instance has no way in. */
|
|
71
93
|
static schemaOf(type: ParamFieldType): JsonSchema;
|
|
@@ -14,7 +14,8 @@ export interface StAgentic {
|
|
|
14
14
|
/** A read-only derived value the agent can read while the component is mounted: `.desc()` then `.value()`. */
|
|
15
15
|
expose: <T extends AgentFieldType>(name: string | null, type: T, meta?: StExposeMeta) => StExposeDraft<T>;
|
|
16
16
|
/**
|
|
17
|
-
* A component tool: `.desc()`, then `.arg()` / `.opt()`, chained onto one `.exec()`
|
|
17
|
+
* A component tool: `.desc()`, then `.arg()` / `.opt()`, chained onto one terminal hook — `.exec()` for a tool
|
|
18
|
+
* a function answers, `.card()` for one the user answers in the chat.
|
|
18
19
|
*
|
|
19
20
|
* A falsy name declares the tool without publishing it — the callable still drives the click a person makes.
|
|
20
21
|
* Every one of these ends in a hook, so a conditional surface withholds the name rather than skipping the chain.
|
package/types/store/baseSt.d.ts
CHANGED
|
@@ -276,7 +276,7 @@ export declare const st: import("./agentic.d.ts").StAgentic & {
|
|
|
276
276
|
innerWidth: (options?: import("./types.d.ts").StoreUseOptions) => number;
|
|
277
277
|
innerHeight: (options?: import("./types.d.ts").StoreUseOptions) => number;
|
|
278
278
|
responsive: (options?: import("./types.d.ts").StoreUseOptions) => "xl" | "lg" | "md" | "sm" | "xs";
|
|
279
|
-
uiOperation: (options?: import("./types.d.ts").StoreUseOptions) => "
|
|
279
|
+
uiOperation: (options?: import("./types.d.ts").StoreUseOptions) => "idle" | "loading" | "sleep";
|
|
280
280
|
messages: (options?: import("./types.d.ts").StoreUseOptions) => {
|
|
281
281
|
type: "info" | "success" | "error" | "warning" | "loading";
|
|
282
282
|
content: string;
|
|
@@ -307,7 +307,7 @@ export declare const st: import("./agentic.d.ts").StAgentic & {
|
|
|
307
307
|
setInnerWidth: (value: number) => void;
|
|
308
308
|
setInnerHeight: (value: number) => void;
|
|
309
309
|
setResponsive: (value: "xl" | "lg" | "md" | "sm" | "xs") => void;
|
|
310
|
-
setUiOperation: (value: "
|
|
310
|
+
setUiOperation: (value: "idle" | "loading" | "sleep") => void;
|
|
311
311
|
setMessages: (value: {
|
|
312
312
|
type: "info" | "success" | "error" | "warning" | "loading";
|
|
313
313
|
content: string;
|
package/types/ui/Agent/Chat.d.ts
CHANGED
|
@@ -97,6 +97,12 @@ export interface ChatProps {
|
|
|
97
97
|
* field reads as a paragraph rather than as the editor document it is stored as.
|
|
98
98
|
*/
|
|
99
99
|
reference?: readonly ReferenceSource[];
|
|
100
|
+
/**
|
|
101
|
+
* Draws each pointer in the composer as the name it points at rather than as the `@[…](mention:…)` token that
|
|
102
|
+
* carries it. On wherever `reference` sources are declared, and `false` keeps the plain textarea — for an app
|
|
103
|
+
* that overrides the composer, or one that would rather see the tokens it is sending.
|
|
104
|
+
*/
|
|
105
|
+
mentions?: boolean;
|
|
100
106
|
/**
|
|
101
107
|
* Raises or lowers what the composer accepts — per file, per message, and how many. The defaults are what one
|
|
102
108
|
* turn's JSON safely carries to a conservative provider; an app pointed at a larger request limit, or one whose
|
|
@@ -117,6 +123,6 @@ export interface ChatProps {
|
|
|
117
123
|
* `persist` keeps it. An enclosing AgentProvider's session wins, which is how an app isolates a surface or swaps
|
|
118
124
|
* the loop while keeping this UI.
|
|
119
125
|
*/
|
|
120
|
-
export declare const DefaultChat: ({ className, title, instructions, runner, maxTurns, compact, builtins, onCompact, defaultOpen, open: openProp, onOpenChange, launcher, visual, persist, inline, shortcut, launcherClassName, panelClassName, intro, header, chrome, defaultDraft, attach, attachLimits, reference, voice, }: ChatProps) => ReactNode;
|
|
126
|
+
export declare const DefaultChat: ({ className, title, instructions, runner, maxTurns, compact, builtins, onCompact, defaultOpen, open: openProp, onOpenChange, launcher, visual, persist, inline, shortcut, launcherClassName, panelClassName, intro, header, chrome, defaultDraft, attach, attachLimits, reference, mentions, voice, }: ChatProps) => ReactNode;
|
|
121
127
|
declare const _default: import("react").ComponentType<ChatProps>;
|
|
122
128
|
export default _default;
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { type KeyboardEvent, type RefObject } from "react";
|
|
2
2
|
import type { AgentSession, MessageAttachment, MessageReference } from "../../vendor/use-agentic.d.ts";
|
|
3
|
+
/**
|
|
4
|
+
* What the chat needs of whatever the composer draws into — a textarea, or the mention editor. Every offset is an
|
|
5
|
+
* offset into the draft string, tokens included, because that is the text the chat reasons about.
|
|
6
|
+
*/
|
|
7
|
+
export interface ComposerHandle {
|
|
8
|
+
focus: () => void;
|
|
9
|
+
caret: () => number | null;
|
|
10
|
+
setCaret: (at: number) => void;
|
|
11
|
+
}
|
|
3
12
|
export interface ComposerProps {
|
|
4
13
|
className?: string;
|
|
5
14
|
session: AgentSession;
|
|
@@ -26,7 +35,14 @@ export interface ComposerProps {
|
|
|
26
35
|
onSend: () => void;
|
|
27
36
|
onStop: () => void;
|
|
28
37
|
inputRef?: RefObject<HTMLTextAreaElement | null>;
|
|
38
|
+
/**
|
|
39
|
+
* Draws each `@` pointer as the name it points at instead of as its token. On only where the chat was given
|
|
40
|
+
* `reference` sources, so an app that declared none never fetches the editor's chunk.
|
|
41
|
+
*/
|
|
42
|
+
mentions?: boolean;
|
|
43
|
+
/** Filled by whichever input is drawn. An override that draws its own textarea leaves it null and `inputRef` answers. */
|
|
44
|
+
handleRef?: RefObject<ComposerHandle | null>;
|
|
29
45
|
}
|
|
30
46
|
/** What the user writes with: the staged files above, and the controls that send or stop below them. */
|
|
31
|
-
export declare const DefaultComposer: ({ className, session, draft, attached, references, pending, mic, onDraft, onKeyDown, onFiles, onRemoveFile, onRemoveReference, onSend, onStop, inputRef, }: ComposerProps) => import("react/jsx-runtime").JSX.Element;
|
|
47
|
+
export declare const DefaultComposer: ({ className, session, draft, attached, references, pending, mic, onDraft, onKeyDown, onFiles, onRemoveFile, onRemoveReference, onSend, onStop, inputRef, mentions, handleRef, }: ComposerProps) => import("react/jsx-runtime").JSX.Element;
|
|
32
48
|
export declare const Composer: import("react").ComponentType<ComposerProps>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type LexicalNode, type NodeKey, type SerializedTextNode, TextNode } from "lexical";
|
|
2
|
+
import { type MessageReference } from "../../vendor/use-agentic.d.ts";
|
|
3
|
+
export interface SerializedMentionNode extends SerializedTextNode {
|
|
4
|
+
reference: MessageReference;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* One `@` pointer inside the composer: the label is what the node draws, and `getTextContent()` is the
|
|
8
|
+
* `@[label](mention:…)` token — so the editor's own text is the draft string the rest of the chat already reads,
|
|
9
|
+
* pointers and all, while the person sees a name.
|
|
10
|
+
*
|
|
11
|
+
* `token` mode is what makes it one thing: the caret never lands inside it, a backspace takes the whole pointer
|
|
12
|
+
* rather than a character of a label that would then name nothing, and a paste over it replaces it entirely.
|
|
13
|
+
*/
|
|
14
|
+
export declare class MentionNode extends TextNode {
|
|
15
|
+
#private;
|
|
16
|
+
static getType(): string;
|
|
17
|
+
static clone(node: MentionNode): MentionNode;
|
|
18
|
+
static importJSON(json: Parameters<typeof TextNode.importJSON>[0]): MentionNode;
|
|
19
|
+
constructor(reference?: MessageReference, key?: NodeKey);
|
|
20
|
+
get reference(): MessageReference;
|
|
21
|
+
getTextContent(): string;
|
|
22
|
+
createDOM(...args: Parameters<TextNode["createDOM"]>): HTMLElement;
|
|
23
|
+
exportJSON(): SerializedMentionNode;
|
|
24
|
+
}
|
|
25
|
+
export declare const $createMentionNode: (reference: MessageReference) => MentionNode;
|
|
26
|
+
export declare const $isMentionNode: (node: LexicalNode | null | undefined) => node is MentionNode;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type KeyboardEvent as ReactKeyboardEvent, type RefObject } from "react";
|
|
2
|
+
import type { ComposerHandle } from "./Composer.d.ts";
|
|
3
|
+
interface RichInputProps {
|
|
4
|
+
className?: string;
|
|
5
|
+
draft: string;
|
|
6
|
+
placeholder: string;
|
|
7
|
+
onDraft: (text: string) => void;
|
|
8
|
+
/** The textarea's own handler, unchanged: the chat reads a key off the draft and the caret, not off the DOM. */
|
|
9
|
+
onKeyDown: (event: ReactKeyboardEvent<HTMLTextAreaElement>) => void;
|
|
10
|
+
onFiles: (files: File[]) => void;
|
|
11
|
+
handleRef?: RefObject<ComposerHandle | null>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The composer's input when the chat has `@` sources: the same draft string, drawn with each pointer as the name
|
|
15
|
+
* it points at instead of as the token that carries it.
|
|
16
|
+
*
|
|
17
|
+
* Lexical rather than a contenteditable of our own, for one reason — a Korean or Japanese IME composing into a
|
|
18
|
+
* contenteditable React also re-renders is the bug class the library exists to own, and it is not one an app can
|
|
19
|
+
* work around from outside.
|
|
20
|
+
*/
|
|
21
|
+
export declare const RichInput: ({ className, draft, placeholder, onDraft, onKeyDown, onFiles, handleRef, }: RichInputProps) => import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export default RichInput;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PendingCard } from "../../vendor/use-agentic.d.ts";
|
|
2
|
+
export interface ToolCardProps {
|
|
3
|
+
className?: string;
|
|
4
|
+
card: PendingCard;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* A call the user answers, parked above the composer where the approval and the question cards sit. What it draws
|
|
8
|
+
* is the app's own — the declaration that published the tool also said what filling it in looks like — so this
|
|
9
|
+
* frame owns only the placement and the way out of it.
|
|
10
|
+
*
|
|
11
|
+
* The way out is not the app's to forget: a card that renders no cancel of its own would otherwise park the turn
|
|
12
|
+
* on a component the user cannot dismiss, so the frame always draws one.
|
|
13
|
+
*/
|
|
14
|
+
export declare const DefaultToolCard: ({ className, card }: ToolCardProps) => import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
declare const _default: import("react").ComponentType<ToolCardProps>;
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type LexicalNode } from "lexical";
|
|
2
|
+
/**
|
|
3
|
+
* The two directions between the composer's draft string and what the editor holds. The string stays the source
|
|
4
|
+
* of truth for the rest of the chat — it is what carries the `@[…](mention:…)` tokens onto the message — and the
|
|
5
|
+
* editor is one way of drawing it, so every offset here is an offset into **that string**, never into what the
|
|
6
|
+
* screen shows.
|
|
7
|
+
*/
|
|
8
|
+
export declare class MentionDraft {
|
|
9
|
+
#private;
|
|
10
|
+
/** Runs inside an editor read or update, like every `$` function. */
|
|
11
|
+
static read(): string;
|
|
12
|
+
/** Rebuilds the whole content from a draft string — the path every write that is not a keystroke takes. */
|
|
13
|
+
static write(text: string, caretAt?: number): void;
|
|
14
|
+
static nodesOf(text: string): LexicalNode[];
|
|
15
|
+
/** Where the caret sits in the draft string, or `null` when there is no collapsed caret to report. */
|
|
16
|
+
static caret(): number | null;
|
|
17
|
+
/** Puts the caret at a draft-string offset. Past the end, or inside a mention, it lands on the nearest edge. */
|
|
18
|
+
static place(at: number): void;
|
|
19
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { type RefObject } from "react";
|
|
2
2
|
import { type AgentSession, type MessageReference } from "../../vendor/use-agentic.d.ts";
|
|
3
|
+
import type { ComposerHandle } from "./Composer.d.ts";
|
|
3
4
|
interface ChatReferencesSetup {
|
|
4
5
|
session: AgentSession;
|
|
5
6
|
draft: string;
|
|
6
7
|
/** The chat's own version snapshot — a `refer` from anywhere on the page is one of the changes it counts. */
|
|
7
8
|
version: number;
|
|
8
|
-
|
|
9
|
+
handleRef: RefObject<ComposerHandle | null>;
|
|
9
10
|
onDraft: (text: string) => void;
|
|
10
11
|
}
|
|
11
12
|
/**
|
|
@@ -18,7 +19,7 @@ interface ChatReferencesSetup {
|
|
|
18
19
|
* whose value was never staged (pasted out of an earlier message) travels as a pointer with a note saying to read
|
|
19
20
|
* it again, which is the same shape a restored conversation produces.
|
|
20
21
|
*/
|
|
21
|
-
export declare const useChatReferences: ({ session, draft, version,
|
|
22
|
+
export declare const useChatReferences: ({ session, draft, version, handleRef, onDraft }: ChatReferencesSetup) => {
|
|
22
23
|
references: MessageReference[];
|
|
23
24
|
/** Removing the chip removes the token, because the token is what puts the reference on the message. */
|
|
24
25
|
remove: (key: string) => void;
|
|
@@ -10,6 +10,7 @@ import type { MenuProps as AgentMenuProps } from "../Agent/Menu.d.ts";
|
|
|
10
10
|
import type { QuestionProps as AgentQuestionProps } from "../Agent/Question.d.ts";
|
|
11
11
|
import type { QueuedProps as AgentQueuedProps } from "../Agent/Queued.d.ts";
|
|
12
12
|
import type { StepsProps as AgentStepsProps } from "../Agent/Steps.d.ts";
|
|
13
|
+
import type { ToolCardProps as AgentToolCardProps } from "../Agent/ToolCard.d.ts";
|
|
13
14
|
import type { BadgeProps } from "../Badge.d.ts";
|
|
14
15
|
import type { ButtonProps } from "../Button.d.ts";
|
|
15
16
|
import type { DatePickerProps, RangePickerProps, TimePickerProps } from "../DatePicker.d.ts";
|
|
@@ -68,6 +69,7 @@ export interface AkanUiOverrides {
|
|
|
68
69
|
AgentQueued: ComponentType<AgentQueuedProps>;
|
|
69
70
|
AgentMenu: ComponentType<AgentMenuProps>;
|
|
70
71
|
AgentMarkdown: ComponentType<AgentMarkdownProps>;
|
|
72
|
+
AgentToolCard: ComponentType<AgentToolCardProps>;
|
|
71
73
|
AgentCode: ComponentType<AgentCodeProps>;
|
|
72
74
|
Button: ComponentType<ButtonProps<unknown>>;
|
|
73
75
|
Select: ComponentType<SelectProps<string | number | boolean | null | undefined>>;
|
package/types/ui/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { type AttachLimits, type AttachReader, maxAttachmentBytes, maxMessageAtt
|
|
|
8
8
|
export { type BubbleProps, DefaultBubble } from "./Agent/Bubble.d.ts";
|
|
9
9
|
export type { ChatProps } from "./Agent/Chat.d.ts";
|
|
10
10
|
export { type ChatCommand, ChatCommands } from "./Agent/ChatCommands.d.ts";
|
|
11
|
-
export { type ComposerProps, DefaultComposer } from "./Agent/Composer.d.ts";
|
|
11
|
+
export { type ComposerHandle, type ComposerProps, DefaultComposer } from "./Agent/Composer.d.ts";
|
|
12
12
|
export { fetchRunner } from "./Agent/fetchRunner.d.ts";
|
|
13
13
|
export type { HistoryProps as AgentHistoryProps } from "./Agent/History.d.ts";
|
|
14
14
|
export { DefaultLauncher, type LauncherProps } from "./Agent/Launcher.d.ts";
|
|
@@ -20,6 +20,7 @@ export { ReferenceChips as AgentReferences, type ReferenceChipsProps as AgentRef
|
|
|
20
20
|
export { DefaultSteps, type StepsProps } from "./Agent/Steps.d.ts";
|
|
21
21
|
export type { PersistOption } from "./Agent/sessionHistory.d.ts";
|
|
22
22
|
export type { AgentBuiltin, BuiltinOption } from "./Agent/sessionView.d.ts";
|
|
23
|
+
export { DefaultToolCard, type ToolCardProps } from "./Agent/ToolCard.d.ts";
|
|
23
24
|
export { tokenCount } from "./Agent/tokenCount.d.ts";
|
|
24
25
|
export type { QueuedMessage } from "./Agent/useChatQueue.d.ts";
|
|
25
26
|
export type { ReferenceCandidate, ReferenceSource } from "./Agent/useReferenceMenu.d.ts";
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
export declare const badgeRecipe: (variants?: Omit<({
|
|
3
3
|
size?: "lg" | "md" | "sm" | "xs" | undefined;
|
|
4
4
|
outline?: boolean | undefined;
|
|
5
|
-
variant?: "default" | "
|
|
5
|
+
variant?: "default" | "error" | "info" | "warning" | "success" | "primary" | "secondary" | "accent" | "neutral" | "outline" | undefined;
|
|
6
6
|
} & {
|
|
7
7
|
class?: import("tailwind-variants").ClassValue;
|
|
8
8
|
className?: never;
|
|
9
9
|
}) | ({
|
|
10
10
|
size?: "lg" | "md" | "sm" | "xs" | undefined;
|
|
11
11
|
outline?: boolean | undefined;
|
|
12
|
-
variant?: "default" | "
|
|
12
|
+
variant?: "default" | "error" | "info" | "warning" | "success" | "primary" | "secondary" | "accent" | "neutral" | "outline" | undefined;
|
|
13
13
|
} & {
|
|
14
14
|
class?: never;
|
|
15
15
|
className?: import("tailwind-variants").ClassValue;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
export declare const buttonRecipe: (variants?: Omit<({
|
|
3
3
|
size?: "lg" | "md" | "sm" | "xs" | "icon" | undefined;
|
|
4
4
|
outline?: boolean | undefined;
|
|
5
|
-
variant?: "link" | "default" | "info" | "
|
|
5
|
+
variant?: "link" | "default" | "info" | "warning" | "success" | "primary" | "secondary" | "accent" | "destructive" | "neutral" | "outline" | "ghost" | undefined;
|
|
6
6
|
shape?: "default" | "circle" | "square" | undefined;
|
|
7
7
|
} & {
|
|
8
8
|
class?: import("tailwind-variants").ClassValue;
|
|
@@ -10,7 +10,7 @@ export declare const buttonRecipe: (variants?: Omit<({
|
|
|
10
10
|
}) | ({
|
|
11
11
|
size?: "lg" | "md" | "sm" | "xs" | "icon" | undefined;
|
|
12
12
|
outline?: boolean | undefined;
|
|
13
|
-
variant?: "link" | "default" | "info" | "
|
|
13
|
+
variant?: "link" | "default" | "info" | "warning" | "success" | "primary" | "secondary" | "accent" | "destructive" | "neutral" | "outline" | "ghost" | undefined;
|
|
14
14
|
shape?: "default" | "circle" | "square" | undefined;
|
|
15
15
|
} & {
|
|
16
16
|
class?: never;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentProgressReport } from "./AgentProgress.d.ts";
|
|
2
2
|
import { type CompactOptions } from "./Compaction.d.ts";
|
|
3
|
-
import type { AgentRunner, ChatMessage, ContextBlock, MessageReference, PublishedTool, SurfaceView, ToolActivity } from "./types.d.ts";
|
|
3
|
+
import type { AgentRunner, ChatMessage, ContextBlock, MessageReference, PublishedTool, SurfaceView, ToolActivity, ToolCard } from "./types.d.ts";
|
|
4
4
|
export interface PendingApproval {
|
|
5
5
|
callId: string;
|
|
6
6
|
name: string;
|
|
@@ -21,6 +21,19 @@ export interface PendingQuestion {
|
|
|
21
21
|
answer: (value: string | string[]) => void;
|
|
22
22
|
dismiss: (reason?: string) => void;
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* A call parked on a component the app declared with the tool — a form to fill in, a choice no list of strings
|
|
26
|
+
* could carry. The loop waits on it exactly as it waits on an approval, and `render` is the app's own, so the
|
|
27
|
+
* framework decides where the card sits and nothing about what it asks.
|
|
28
|
+
*/
|
|
29
|
+
export interface PendingCard {
|
|
30
|
+
callId: string;
|
|
31
|
+
name: string;
|
|
32
|
+
args: Record<string, unknown>;
|
|
33
|
+
render: ToolCard;
|
|
34
|
+
submit: (value: unknown) => void;
|
|
35
|
+
dismiss: (reason?: string) => void;
|
|
36
|
+
}
|
|
24
37
|
/**
|
|
25
38
|
* Where a session keeps its transcript across page loads. Storage-neutral: the host decides what backs it, so a
|
|
26
39
|
* server-side transcript is as legal as web storage — which is why every method may answer asynchronously. A
|
|
@@ -126,6 +139,7 @@ export declare class AgentSession {
|
|
|
126
139
|
get isCompacting(): boolean;
|
|
127
140
|
get pendingApproval(): PendingApproval | null;
|
|
128
141
|
get pendingQuestion(): PendingQuestion | null;
|
|
142
|
+
get pendingCard(): PendingCard | null;
|
|
129
143
|
/**
|
|
130
144
|
* What the user has pointed at and not yet sent.
|
|
131
145
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type AgentProgressReport } from "./AgentProgress.d.ts";
|
|
2
|
-
import type { SurfaceView, ToolActivity, ToolCallRequest, ToolCallResult, ToolEntry } from "./types.d.ts";
|
|
2
|
+
import type { SurfaceView, ToolActivity, ToolCallRequest, ToolCallResult, ToolCard, ToolEntry } from "./types.d.ts";
|
|
3
3
|
export interface ToolApprovalRequest {
|
|
4
4
|
callId: string;
|
|
5
5
|
name: string;
|
|
@@ -7,6 +7,19 @@ export interface ToolApprovalRequest {
|
|
|
7
7
|
/** What the user is asked, already resolved from the entry's `confirm`. */
|
|
8
8
|
message: string;
|
|
9
9
|
}
|
|
10
|
+
/** A call whose answer the user writes, handed to the host with the component its declaration named. */
|
|
11
|
+
export interface ToolCardRequest {
|
|
12
|
+
callId: string;
|
|
13
|
+
name: string;
|
|
14
|
+
args: Record<string, unknown>;
|
|
15
|
+
render: ToolCard;
|
|
16
|
+
}
|
|
17
|
+
/** What the card settled on: the value the model reads back, or why there is none. */
|
|
18
|
+
export type ToolCardAnswer = {
|
|
19
|
+
result: unknown;
|
|
20
|
+
} | {
|
|
21
|
+
error: string;
|
|
22
|
+
};
|
|
10
23
|
/** `report` is `null` once the call is over, carrying the id so a host can ignore a clear that is not its own. */
|
|
11
24
|
export interface ToolProgress {
|
|
12
25
|
callId: string;
|
|
@@ -25,6 +38,13 @@ export interface ToolRunnerHost {
|
|
|
25
38
|
* a host that may not perform the action, and the refusal says so rather than silently downgrading the gate.
|
|
26
39
|
*/
|
|
27
40
|
approve?: (request: ToolApprovalRequest, signal: AbortSignal) => Promise<true | string>;
|
|
41
|
+
/**
|
|
42
|
+
* Parks the call until the user fills in the card its declaration named, and answers with what they submitted.
|
|
43
|
+
*
|
|
44
|
+
* Omitting it refuses those calls rather than running something in their place: a card tool has no function to
|
|
45
|
+
* fall back to — the user *is* the implementation — so a host with nowhere to render one may not answer it.
|
|
46
|
+
*/
|
|
47
|
+
card?: (request: ToolCardRequest, signal: AbortSignal) => Promise<ToolCardAnswer>;
|
|
28
48
|
/**
|
|
29
49
|
* Awaited after a tool that changed something and before its change report is taken. A surface is read
|
|
30
50
|
* synchronously and a screen does not settle synchronously, so without this the report describes the moment
|
|
@@ -1,9 +1,25 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
1
2
|
export type JsonSchema = Record<string, unknown>;
|
|
2
3
|
/** `true` asks with a default message, a string is the message, a function decides from the arguments. */
|
|
3
4
|
export type ToolConfirm = boolean | string | ((args: Record<string, unknown>) => string | boolean);
|
|
4
5
|
/** Re-checked at the moment of execution; a string is the refusal reason the agent reads. */
|
|
5
6
|
export type ToolGuard = (args: Record<string, unknown>) => true | string;
|
|
6
|
-
|
|
7
|
+
/**
|
|
8
|
+
* What a card tool renders while its call waits, and the two ways the user ends that wait. `submit` is the call's
|
|
9
|
+
* result, `cancel` is its refusal; whichever comes first settles the call and takes the card off the screen, so a
|
|
10
|
+
* second call of either does nothing.
|
|
11
|
+
*/
|
|
12
|
+
export interface ToolCardControl {
|
|
13
|
+
args: Record<string, unknown>;
|
|
14
|
+
submit: (value: unknown) => void;
|
|
15
|
+
cancel: (reason?: string) => void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Called, not mounted — the host invokes it inside its own render, so the returned tree keeps no state of its
|
|
19
|
+
* own between renders. Put anything stateful in a component the function returns.
|
|
20
|
+
*/
|
|
21
|
+
export type ToolCard = (control: ToolCardControl) => ReactNode;
|
|
22
|
+
interface ToolEntryBase {
|
|
7
23
|
name: string;
|
|
8
24
|
description?: string;
|
|
9
25
|
parameters?: JsonSchema;
|
|
@@ -14,8 +30,21 @@ export interface ToolEntry {
|
|
|
14
30
|
settle?: boolean;
|
|
15
31
|
confirm?: ToolConfirm;
|
|
16
32
|
guard?: ToolGuard;
|
|
33
|
+
}
|
|
34
|
+
export interface ToolActionEntry extends ToolEntryBase {
|
|
17
35
|
run: (args: Record<string, unknown>) => unknown;
|
|
36
|
+
card?: never;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A call the **user** answers rather than the screen: the host parks the call, renders `card`, and what the card
|
|
40
|
+
* submits is what the model reads back. `confirm` is not read for one — the card in front of the user is already
|
|
41
|
+
* the asking, and a gate before it would ask them twice for one thing.
|
|
42
|
+
*/
|
|
43
|
+
export interface ToolCardEntry extends ToolEntryBase {
|
|
44
|
+
card: ToolCard;
|
|
45
|
+
run?: never;
|
|
18
46
|
}
|
|
47
|
+
export type ToolEntry = ToolActionEntry | ToolCardEntry;
|
|
19
48
|
/**
|
|
20
49
|
* That a call is happening, for a host drawing it on the screen rather than in a transcript.
|
|
21
50
|
*
|
|
@@ -236,3 +265,4 @@ export interface RunnerRequest {
|
|
|
236
265
|
export interface AgentRunner {
|
|
237
266
|
run: (request: RunnerRequest) => AsyncIterable<RunnerEvent>;
|
|
238
267
|
}
|
|
268
|
+
export {};
|