@llmnative/agentico 0.2.0 → 0.4.0

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.
@@ -1,5 +1,6 @@
1
1
  import type { z } from 'zod';
2
2
  import type { AIAttachment } from '@llmnative/react';
3
+ import type { AgentQuestion, AgentQuestionAnswer, AgentQuestionsAnswers } from './messageParts';
3
4
  /** Rif mutabile, sempre aggiornato da useAgent.ts all'inizio di ogni turno (roundTrip 0) con
4
5
  * gli allegati grezzi (base64) di QUESTO turno — mai un valore statico catturato una volta:
5
6
  * un tool creato da getTools() (chiamato una sola volta per sessione) deve comunque vedere gli
@@ -108,10 +109,40 @@ export interface AgentExecutorTurn<TParams, TContext> {
108
109
  signal: AbortSignal;
109
110
  /** The model the person picked among `AgentExecutor.models`, if the executor offers any. */
110
111
  model?: string;
111
- /** The reply so far, whole (not a delta): shown as it grows. */
112
- onText(text: string): void;
113
- /** A step of the agent: added the first time its id is seen, updated after. */
112
+ /** Present when the person answered questions of an earlier turn (CR-004): the turn carries
113
+ * them, structured, with `text` empty. The executor decides how to forward them (e.g. to the
114
+ * `question` tool of its session). Questions answered while their own turn is still running
115
+ * resolve the promise of `onQuestions` instead. */
116
+ answers?: AgentQuestionsAnswers;
117
+ /** The reply so far, whole (not a delta): shown as it grows, as Markdown. Without `part.id` it
118
+ * is the one reply of the turn (CR-003), kept below the steps and the reasoning; with an id it is
119
+ * a text part of its own, in the order it first arrived (CR-004). `part.done` ends its streaming. */
120
+ onText(text: string, part?: AgentExecutorPartOptions): void;
121
+ /** The reasoning of the model so far, whole (not a delta), as Markdown: shown closed behind
122
+ * "Reasoned for 12 s" (CR-004). Without `part.id` it is one reasoning part per turn. It ends with
123
+ * `part.done`, when another kind of part arrives, or with the turn; `part.duration` (seconds)
124
+ * replaces the time Agentico measures. */
125
+ onReasoning(text: string, part?: AgentExecutorPartOptions & {
126
+ duration?: number;
127
+ }): void;
128
+ /** A step of the agent: added the first time its id is seen, updated after. Consecutive steps
129
+ * are shown as one collapsible group. */
114
130
  onStep(step: AgentExecutorStep): void;
131
+ /** Questions to the person, answered with a click (CR-004). The promise resolves with the
132
+ * answers if they come while this turn is still running (e.g. the session waits for them);
133
+ * once the turn has ended (or the chat was reloaded), the answers arrive as a new turn with
134
+ * `answers` instead. It rejects when the person stops the turn. `part.id` names the set
135
+ * (default: made up by Agentico) and is the `answers.id` of that later turn. */
136
+ onQuestions(questions: AgentQuestion[], part?: {
137
+ id?: string;
138
+ }): Promise<AgentQuestionAnswer[]>;
139
+ }
140
+ /** Which part an `onText`/`onReasoning` call updates, and whether it is complete. */
141
+ export interface AgentExecutorPartOptions {
142
+ /** The part to update: created the first time it is seen. */
143
+ id?: string;
144
+ /** The part is complete: no longer streaming. */
145
+ done?: boolean;
115
146
  }
116
147
  /** The host side of a remote agent: one call per turn, resolved when its reply is complete. */
117
148
  export interface AgentExecutor<TParams, TContext, TResult> {
@@ -1,4 +1,5 @@
1
1
  import type { AIConversationTurn } from '@llmnative/react';
2
+ import type { AgentMessagePart } from './messageParts';
2
3
  /** Stessa forma di AgentActivityEntry (agentico/presentation/useAgent.ts) — ridefinita qui invece
3
4
  * di importata: il domain layer non dipende dal presentation layer, e questi campi sono
4
5
  * semplici dati (mai funzioni), quindi TypeScript accetta un AgentActivityEntry[] ovunque sia
@@ -10,6 +11,10 @@ export interface EntityChatActivityEntry {
10
11
  status: 'running' | 'done' | 'error' | 'stopped';
11
12
  detail?: string;
12
13
  toolNames?: string[];
14
+ attachmentNames?: string[];
15
+ /** The message in parts (CR-004): saved and reloaded as they are. Absent in chats saved before
16
+ * 0.3.0, which show `detail` as before. */
17
+ parts?: AgentMessagePart[];
13
18
  }
14
19
  export interface EntityChatSnapshot {
15
20
  /** Host scope (tenant, company…) the chat belongs to — see AgenticoScope. */
@@ -0,0 +1,79 @@
1
+ /** A choice of a question (the shape of the `question` tool of opencode and of MCP elicitation). */
2
+ export interface AgentQuestionOption {
3
+ /** What the answer says: it is the value returned when chosen. */
4
+ label: string;
5
+ /** A line under the label. */
6
+ description?: string;
7
+ }
8
+ /** A question of the agent to the person. */
9
+ export interface AgentQuestion {
10
+ /** Returned with the answer, to match it to the question. */
11
+ id?: string;
12
+ /** Short title: the label of its tab. */
13
+ header?: string;
14
+ question: string;
15
+ /** The choices. Without them the question takes a free-text answer. */
16
+ options?: AgentQuestionOption[];
17
+ /** More than one choice. */
18
+ multiple?: boolean;
19
+ /** The choice the agent recommends: its index (from 0) or its label. */
20
+ recommended?: number | string;
21
+ /** Offers "Other" with a free-text answer (default: yes). */
22
+ custom?: boolean;
23
+ }
24
+ /** The answer to one question: the chosen labels and/or the free text, in the order of the questions. */
25
+ export interface AgentQuestionAnswer {
26
+ id?: string;
27
+ header?: string;
28
+ values: string[];
29
+ }
30
+ /** The answers to a set of questions, as a turn gives them to the executor. `id` is the id of the
31
+ * questions part (the one given to `onQuestions`, or the one Agentico made up). */
32
+ export interface AgentQuestionsAnswers {
33
+ id: string;
34
+ answers: AgentQuestionAnswer[];
35
+ }
36
+ /** Text of the reply, as Markdown. `streaming` while it is still arriving. */
37
+ export interface AgentTextPart {
38
+ type: 'text';
39
+ id: string;
40
+ text: string;
41
+ streaming?: boolean;
42
+ }
43
+ /** The reasoning of the model, as Markdown, shown closed behind "Reasoned for 12 s". */
44
+ export interface AgentReasoningPart {
45
+ type: 'reasoning';
46
+ id: string;
47
+ text: string;
48
+ streaming?: boolean;
49
+ /** Seconds the model reasoned: given by the executor, or measured by Agentico. */
50
+ duration?: number;
51
+ }
52
+ /** A step of the agent (a tool it ran, a file it wrote). Consecutive steps are shown as one group. */
53
+ export interface AgentToolPart {
54
+ type: 'tool';
55
+ id: string;
56
+ label: string;
57
+ status: 'running' | 'done' | 'error' | 'stopped';
58
+ }
59
+ /** Questions to the person, answered with a click. `answers` once answered (shown read-only). */
60
+ export interface AgentQuestionsPart {
61
+ type: 'questions';
62
+ id: string;
63
+ questions: AgentQuestion[];
64
+ answers?: AgentQuestionAnswer[];
65
+ }
66
+ export type AgentMessagePart = AgentTextPart | AgentReasoningPart | AgentToolPart | AgentQuestionsPart;
67
+ /** The id of the text part of an executor that calls `onText` without an id (the reply of CR-003). */
68
+ export declare const DEFAULT_TEXT_PART_ID = "text";
69
+ /** The id of the reasoning part of an executor that calls `onReasoning` without an id. */
70
+ export declare const DEFAULT_REASONING_PART_ID = "reasoning";
71
+ /** Adds `part`, or replaces the part of the same type and id. A new step or reasoning goes above the
72
+ * default text part, so the reply (as in CR-003) stays below the work that led to it; anything else
73
+ * is appended. `closeReasoning` closes the reasoning still streaming when a part of another type
74
+ * arrives (the model moved on), with its duration. */
75
+ export declare function upsertMessagePart(parts: AgentMessagePart[], part: AgentMessagePart, closeReasoning?: (part: AgentReasoningPart) => AgentReasoningPart): AgentMessagePart[];
76
+ /** The text of a message: its text parts, one paragraph each (what `AgentActivityEntry.detail` holds). */
77
+ export declare function messagePartsText(parts: readonly AgentMessagePart[]): string;
78
+ /** The answers as one line per question ("Database: Postgres"), for the history of the chat. */
79
+ export declare function formatQuestionAnswers(questions: readonly AgentQuestion[], answers: readonly AgentQuestionAnswer[]): string;
@@ -31,6 +31,12 @@ export interface AgenticoDict {
31
31
  tooManyToolTurns: string;
32
32
  aiDisabledFallback: string;
33
33
  continueWithoutAiFallback: string;
34
+ /** The group of the steps of the agent, when it holds one step. */
35
+ oneStep: string;
36
+ /** The group of the steps of the agent. `{count}` = number of steps */
37
+ steps: string;
38
+ /** Accessible name of the group of the steps. */
39
+ stepsLabel: string;
34
40
  /** `{label}` = subagent label */
35
41
  newInstance: string;
36
42
  chatHistory: string;
@@ -49,6 +55,14 @@ export interface AgenticoDict {
49
55
  resumeWithAi: string;
50
56
  openPanel: string;
51
57
  closePanel: string;
58
+ /** Accessible name of the edge that resizes the panel. */
59
+ resizePanel: string;
60
+ /** Tooltip of that edge. */
61
+ resizePanelHint: string;
62
+ /** Accessible name of the questions docked at the bottom of the panel. */
63
+ pendingQuestions: string;
64
+ /** Stops the turn while its questions are docked (the composer, with its stop button, is hidden). */
65
+ stop: string;
52
66
  }
53
67
  declare module '@llmnative/react' {
54
68
  interface I18nDict {
@@ -1,5 +1,6 @@
1
1
  import './i18n/types';
2
- export type { AgentDefinition, AgentTool, LatestAttachmentsRef, AgentExecutor, AgentExecutorTurn, AgentExecutorStep } from './domain/agentDefinition';
2
+ export type { AgentDefinition, AgentTool, LatestAttachmentsRef, AgentExecutor, AgentExecutorTurn, AgentExecutorStep, AgentExecutorPartOptions } from './domain/agentDefinition';
3
+ export { DEFAULT_TEXT_PART_ID, DEFAULT_REASONING_PART_ID, upsertMessagePart, messagePartsText, formatQuestionAnswers, type AgentMessagePart, type AgentTextPart, type AgentReasoningPart, type AgentToolPart, type AgentQuestionsPart, type AgentQuestion, type AgentQuestionOption, type AgentQuestionAnswer, type AgentQuestionsAnswers, } from './domain/messageParts';
3
4
  export type { SubagentCommand, SubagentManifest, SubagentComponentContext } from './domain/subagentManifest';
4
5
  export { defineSubagent } from './domain/defineSubagent';
5
6
  export { registerSubagents, getSubagentRegistry, findSubagentManifest } from './domain/subagentRegistry';
@@ -16,7 +17,8 @@ export { jsonExportDestination, JSON_EXPORT_DESTINATION_ID } from './domain/json
16
17
  export { registerDestinations, getDestinationRegistry } from './domain/destinationRegistry';
17
18
  export { configureEntityChatStore, saveEntityChat, getEntityChat, listEntityChats, removeEntityChat, entityChatTaskId, type EntityChatSnapshot, } from './domain/entityChatStore';
18
19
  export { agenticoTranslations, agenticoEn, agenticoIt, agenticoDe, useAgenticoI18n, type AgenticoDict } from './i18n';
19
- export { Agentico, AGENTICO_WIDTH } from './presentation/Agentico';
20
+ export { Agentico, AGENTICO_WIDTH, type AgenticoProps } from './presentation/Agentico';
21
+ export { AGENTICO_MIN_WIDTH, AGENTICO_MAX_WIDTH, AGENTICO_WIDTH_STORAGE_KEY, type AgenticoPanelSize } from './presentation/panelWidth';
20
22
  export { AgenticoToggle } from './presentation/AgenticoToggle';
21
23
  export { AgenticoProvider, useAgentico, ORCHESTRATOR_TASK_ID, type AgenticoScope, type AgenticoTask, type ComponentAnchor, } from './presentation/AgenticoContext';
22
24
  export { useAgent, type AgentActivityEntry, type AgentConversation, type UseAgentResult } from './presentation/useAgent';
@@ -1,9 +1,45 @@
1
- import React from 'react';
2
1
  import type { AgentActivityEntry } from './useAgent';
2
+ import type { AgentQuestionAnswer, AgentQuestionsPart } from '../domain/messageParts';
3
+ /** What the log needs to let the person answer questions (CR-004): the entries of the live
4
+ * conversation (`canAnswer`) and where the answers go. Without it, unanswered questions are shown
5
+ * disabled. */
6
+ export interface AgentActivityLogQuestions {
7
+ canAnswer: (entryId: string) => boolean;
8
+ onAnswer: (entryId: string, partId: string, answers: AgentQuestionAnswer[]) => Promise<unknown>;
9
+ }
10
+ /** The questions part shown docked at the bottom of the panel instead of in the thread (CR-005). */
11
+ export interface DockedQuestions {
12
+ entry: AgentActivityEntry;
13
+ part: AgentQuestionsPart;
14
+ }
15
+ /** The questions waiting for an answer in the latest message of the agent (CR-005): the last
16
+ * questions part without answers of the last entry, when that entry is a message in parts of a turn
17
+ * that did not stop or fail, and the person can answer it. Otherwise nothing is docked and the
18
+ * questions stay in the thread (read-only once answered). */
19
+ export declare function findDockedQuestions(activity: readonly AgentActivityEntry[], canAnswer: (entryId: string) => boolean): DockedQuestions | null;
20
+ /** A questions part of the agent with `ChatQuestions`: answerable while the entry is live and it has
21
+ * no answers, read-only with its answers, disabled otherwise. */
22
+ export declare function QuestionsPart({ entry, part, questions, autoFocus, className }: {
23
+ entry: AgentActivityEntry;
24
+ part: AgentQuestionsPart;
25
+ questions?: AgentActivityLogQuestions;
26
+ autoFocus?: boolean;
27
+ className?: string;
28
+ }): import("react").JSX.Element;
3
29
  /** Il log di attività di un agente, usato dal pannello globale (Agentico) — ogni agente ora
4
30
  * ci passa attraverso, il pannello embedded legacy (AgentFollowUp) è stato ritirato una volta
5
31
  * migrato anche l'ultimo consumer (import HTML/JSX, vedi ComponentEditPage.tsx). Un solo posto
6
- * per l'icon-system e la logica "sto pensando" transitorio/collassabile. */
7
- export declare function AgentActivityLog({ activity }: {
32
+ * per l'icon-system e la logica "sto pensando" transitorio/collassabile.
33
+ *
34
+ * One `<li>` per turn (CR-004): the message of the person, sticky at the top while its turn
35
+ * scrolls, then what the agent did and said. Entries before the first message of the person
36
+ * (an opening without text) form a turn of their own, without a bubble. */
37
+ export declare function AgentActivityLog({ activity, questions, docked, pinUserMessages }: {
8
38
  activity: AgentActivityEntry[];
9
- }): React.JSX.Element | null;
39
+ questions?: AgentActivityLogQuestions;
40
+ /** Questions docked at the bottom of the panel (CR-005): left out of the thread. */
41
+ docked?: DockedQuestions | null;
42
+ /** The message of the person sticks at the top while its turn scrolls (default). Off while
43
+ * questions are docked, so the thread has more room. */
44
+ pinUserMessages?: boolean;
45
+ }): import("react").JSX.Element | null;
@@ -1,7 +1,17 @@
1
1
  import React from 'react';
2
- /** Larghezza fissa del pannello — passata anche come `rightInset` alle Modal che devono
3
- * lasciargli spazio invece di sovrapporlo (vedi Modal.rightInset nel framework). */
4
- export declare const AGENTICO_WIDTH = 420;
2
+ import { AGENTICO_WIDTH, type AgenticoPanelSize } from './panelWidth';
3
+ export { AGENTICO_WIDTH };
4
+ /** Props of the panel (CR-005): its width, which the person changes by dragging its inner edge. */
5
+ export interface AgenticoProps {
6
+ /** Width when nothing is stored, and after a double click on the edge. Default `AGENTICO_WIDTH` (420 px). */
7
+ defaultWidth?: number;
8
+ /** Narrowest width, in px. Default 320. */
9
+ minWidth?: number;
10
+ /** Widest width: px, or a share of the viewport (`'60vw'`, the default). */
11
+ maxWidth?: AgenticoPanelSize;
12
+ /** The current width, whenever it changes (e.g. for the `rightInset` of a Modal beside the panel). */
13
+ onWidthChange?: (width: number) => void;
14
+ }
5
15
  /** Agentico — il pannello globale, persistente e non-overlay per le sessioni agente — affianca
6
16
  * il CMS (che si stringe) invece di coprirlo, cosi la modale che ha avviato l'agente resta
7
17
  * aperta e utilizzabile accanto. Header: titolo dell'UNICO task attivo (mai una tab bar — "una
@@ -20,4 +30,4 @@ export declare const AGENTICO_WIDTH = 420;
20
30
  * (AgenticoContext), il suo toggle (AgenticoToggle) — non degli agenti verticali che esegue
21
31
  * (theme-import, html-to-liquid, ...), che restano nel proprio dominio senza questo
22
32
  * prefisso: sono contenuto che Agentico orchestra, non parte della sua identità. */
23
- export declare function Agentico(): React.JSX.Element;
33
+ export declare function Agentico({ defaultWidth, minWidth, maxWidth, onWidthChange }?: AgenticoProps): React.JSX.Element;
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ /** The inner edge of the Agentico column (CR-005), the one facing the page: dragged with the
3
+ * pointer it resizes the panel; focused, the arrow keys do (Shift for bigger steps, Home/End for
4
+ * the minimum/maximum); a double click goes back to the default width. The framework has no
5
+ * splitter primitive, so this one is drawn with theme tokens only: a thin line in the primary
6
+ * colour on hover, focus and while dragging. The panel sits on the right, so moving the edge to
7
+ * the left makes it wider. */
8
+ export declare function AgenticoResizeHandle({ width, min, max, onResize, onCommit, onReset }: {
9
+ width: number;
10
+ min: number;
11
+ max: number;
12
+ /** A new width while it changes (clamped by the caller). */
13
+ onResize: (width: number) => void;
14
+ /** The width the person settled on: stored. */
15
+ onCommit: (width: number) => void;
16
+ onReset: () => void;
17
+ }): React.JSX.Element;
@@ -0,0 +1,32 @@
1
+ /** Default width of the panel, in px. Also the `rightInset` a host can give a Modal that must leave it room. */
2
+ export declare const AGENTICO_WIDTH = 420;
3
+ /** Default minimum width of the panel, in px. */
4
+ export declare const AGENTICO_MIN_WIDTH = 320;
5
+ /** Default maximum width of the panel: a share of the viewport. */
6
+ export declare const AGENTICO_MAX_WIDTH = "60vw";
7
+ /** Where the width chosen by the person is kept, per browser. */
8
+ export declare const AGENTICO_WIDTH_STORAGE_KEY = "agentico:panel-width";
9
+ /** One arrow key press, in px (with Shift: four times as much). */
10
+ export declare const AGENTICO_WIDTH_STEP = 16;
11
+ /** A width in px, or a share of the viewport (`'60vw'`). */
12
+ export type AgenticoPanelSize = number | `${number}vw`;
13
+ /** A size in px: a number as it is, `'<n>vw'` as that share of `viewportWidth`. */
14
+ export declare function resolvePanelSize(size: AgenticoPanelSize, viewportWidth: number): number;
15
+ /** `width` kept between `min` and `max` (a max below the min gives way to the min). */
16
+ export declare function clampPanelWidth(width: number, min: number, max: number): number;
17
+ export interface PanelWidthOptions {
18
+ defaultWidth?: number;
19
+ minWidth?: number;
20
+ maxWidth?: AgenticoPanelSize;
21
+ onWidthChange?: (width: number) => void;
22
+ }
23
+ /** The width of the panel: the stored one or the default, clamped to the current viewport. `set`
24
+ * changes it (clamped), `commit` stores it, `reset` goes back to the default and forgets it. */
25
+ export declare function usePanelWidth({ defaultWidth, minWidth, maxWidth, onWidthChange }: PanelWidthOptions): {
26
+ width: number;
27
+ min: number;
28
+ max: number;
29
+ set: (next: number) => void;
30
+ commit: (next: number) => void;
31
+ reset: () => void;
32
+ };
@@ -1,5 +1,6 @@
1
1
  import type { AIConversationTurn, AIModelDescriptor } from '@llmnative/react';
2
2
  import type { AgentDefinition } from '../domain/agentDefinition';
3
+ import { type AgentMessagePart, type AgentQuestionAnswer } from '../domain/messageParts';
3
4
  /** Una voce del log di attività — o un messaggio dell'utente (il testo di sendMessage(),
4
5
  * mostrato subito com'è, mai "sto pensando" perché non è il modello a scriverlo), o una tool
5
6
  * call (etichetta SEMPRE deterministica/locale, vedi AgentTool.describeInvocation: mai testo
@@ -36,6 +37,10 @@ export interface AgentActivityEntry {
36
37
  * doveva fidarsi a memoria (bug osservato: un allegato sembrava "sparito" perché non
37
38
  * c'era traccia visiva che fosse mai arrivato). */
38
39
  attachmentNames?: string[];
40
+ /** On the turns of a remote agent (CR-004): the message in parts (text, reasoning, steps,
41
+ * questions), in the order they arrived. `detail` still holds its text. Absent on the turns of
42
+ * the AI provider and on chats saved before 0.3.0, shown from `detail` as before. */
43
+ parts?: AgentMessagePart[];
39
44
  }
40
45
  /** Stato di gating/selezione — non generico, condiviso dal componente <AgentControls />
41
46
  * (che non ha bisogno di conoscere TParams/TResult, solo di disegnare switch + select). */
@@ -139,11 +144,17 @@ export interface UseAgentResult<TParams, TResult> extends AgentControlState {
139
144
  history: AIConversationTurn[];
140
145
  activity: AgentActivityEntry[];
141
146
  } | null;
147
+ /** Answers the questions part `partId` of the entry `entryId` (CR-004). If the turn that asked
148
+ * is still waiting, its `onQuestions` promise resolves; otherwise a new turn of the executor
149
+ * carries them (`AgentExecutorTurn.answers`, with empty `text`). Either way the part keeps the
150
+ * answers and shows them read-only. Resolves with the result of that new turn, if any; rejects
151
+ * (leaving the form open) when another turn is running or the entry is not of this conversation. */
152
+ answerQuestions: (entryId: string, partId: string, answers: AgentQuestionAnswer[]) => Promise<TResult | null>;
142
153
  }
143
154
  /** Solo la fetta di UseAgentResult che serve a un consumer del pannello globale (Agentico.tsx)
144
155
  * per continuare una conversazione già avviata da run() — TParams non compare in nessuno dei
145
156
  * membri qui sotto, quindi `never` è innocuo. */
146
- export type AgentConversation<TResult> = Pick<UseAgentResult<never, TResult>, 'canContinue' | 'remote' | 'remoteModels' | 'running' | 'error' | 'activity' | 'sendMessage' | 'stop' | 'runFallback' | 'snapshot'>;
157
+ export type AgentConversation<TResult> = Pick<UseAgentResult<never, TResult>, 'canContinue' | 'remote' | 'remoteModels' | 'running' | 'error' | 'activity' | 'sendMessage' | 'stop' | 'runFallback' | 'snapshot' | 'answerQuestions'>;
147
158
  export declare function useAgent<TParams, TContext, TResult>(definition: AgentDefinition<TParams, TContext, TResult>, options?: {
148
159
  defaultEnabled?: boolean;
149
160
  }): UseAgentResult<TParams, TResult>;
package/llms.txt CHANGED
@@ -25,6 +25,8 @@
25
25
  </AgenticoProvider>
26
26
  ```
27
27
 
28
+ `<Agentico defaultWidth? minWidth? maxWidth? onWidthChange? />` (0.4.0): the column is resized by dragging its inner edge (a `role="separator"`: arrows by 16 px, Shift ×4, Home/End, double click = default), clamped to `minWidth` (320) … `maxWidth` (px or `'<n>vw'`, default `'60vw'`), stored per browser under `agentico:panel-width`. Defaults `AGENTICO_WIDTH` (420), `AGENTICO_MIN_WIDTH`, `AGENTICO_MAX_WIDTH`. Unanswered questions of the latest agent message (turn not stopped/failed) are docked at the bottom in place of the composer (scroll inside, Stop while the turn runs), the person's message is not pinned meanwhile; once answered they are back in the thread, read-only. Questions of a reloaded chat are answerable (docked) too.
29
+
28
30
  ## Hooks
29
31
 
30
32
  - `useAgentico()` — panel state, `startOrchestrator(goal, opts)`, `startSubagent(subagentId, params, { taskId?, openingMessage? })` (use `entityChatTaskId(subagentId, entityId)` as taskId), `resumeEntityChat`, `commitEntityChat(subagentId, entityId, taskId, scopeId, params, title)`, `scope`.
@@ -37,3 +39,5 @@
37
39
  buildContext (always runs) · buildPrompt · buildFollowUpPrompt · parseResponse (null → fallback) · fallback (required) · describeFallback? · getTools? · microPromptIds? · executor?
38
40
 
39
41
  `executor.turn({ params, context, text, first, signal, model?, onText(whole reply so far), onStep({ id, label, status }) }) → { text, result? }`; `executor.models(params)` / `defaultModel(params)` put the models of the executor in the composer: the turns go to the host instead of the AI provider; `text` is what the person typed (opening message on the first turn). The conversation is `remote: true`: no attachments, no fallback; the picker shows `remoteModels`.
42
+
43
+ Message parts (0.3.0): the turn also has `onText(text, { id?, done? })` (without id: the one reply, kept below steps and reasoning; with id: a text part of its own), `onReasoning(text, { id?, done?, duration? })` (whole text so far; shown closed, "Reasoned for N s", duration measured if not given), `onQuestions(questions, { id? }) → Promise<answers>` (questions `{ id?, header?, question, options?: [{ label, description? }], multiple?, recommended?, custom? }`; answers `[{ id?, header?, values: string[] }]`). Answers given while the turn runs resolve that promise; given later (or after a reload) they start a new turn with `text: ''` and `answers: { id, answers }` (id = the questions part id, default `questions-N`). Parts are kept in `AgentActivityEntry.parts` (`text` | `reasoning` | `tool` | `questions`, `detail` = the text) and saved with the chat; old chats without parts show `detail`. Rendered with `ChatMarkdown`, `ChatReasoning`, steps grouped in a `Tree`, `ChatQuestions` (needs `@llmnative/react` 1.34). `useAgent().answerQuestions(entryId, partId, answers)`.
package/package.json CHANGED
@@ -1,79 +1,79 @@
1
- {
2
- "name": "@llmnative/agentico",
3
- "version": "0.2.0",
4
- "description": "Agentic chat orchestrator for @llmnative/react apps: a persistent panel that talks with the user and hands the work to host-registered subagents.",
5
- "main": "dist/index.js",
6
- "module": "dist/index.mjs",
7
- "types": "dist/types/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/types/index.d.ts",
11
- "import": "./dist/index.mjs",
12
- "require": "./dist/index.js"
13
- }
14
- },
15
- "files": [
16
- "dist",
17
- "llms.txt"
18
- ],
19
- "sideEffects": false,
20
- "scripts": {
21
- "build": "vite build && tsc -p tsconfig.build.json",
22
- "typecheck": "tsc --noEmit",
23
- "test": "vitest run",
24
- "test:watch": "vitest",
25
- "prepublishOnly": "npm run build",
26
- "release:check": "node scripts/release/check-release.mjs"
27
- },
28
- "repository": {
29
- "type": "git",
30
- "url": "git+https://github.com/sherpadvisorylab/llmnative-agentico.git"
31
- },
32
- "bugs": {
33
- "url": "https://github.com/sherpadvisorylab/llmnative-agentico/issues"
34
- },
35
- "homepage": "https://github.com/sherpadvisorylab/llmnative-agentico#readme",
36
- "keywords": [
37
- "llmnative",
38
- "agent",
39
- "orchestrator",
40
- "subagent",
41
- "ai",
42
- "react"
43
- ],
44
- "author": "wolfgan",
45
- "license": "Apache-2.0",
46
- "engines": {
47
- "node": ">=24.18.0 <25"
48
- },
49
- "packageManager": "npm@11.11.0",
50
- "peerDependencies": {
51
- "@llmnative/react": "^1.31.0",
52
- "react": "^19.2.0",
53
- "react-dom": "^19.2.0",
54
- "zod": "^3.24.1"
55
- },
56
- "dependencies": {
57
- "zod-to-json-schema": "^3.24.1"
58
- },
59
- "devDependencies": {
60
- "@llmnative/react": "^1.31.0",
61
- "@phosphor-icons/react": "^2.1.10",
62
- "@testing-library/jest-dom": "^7.0.1",
63
- "@testing-library/react": "^16.3.3",
64
- "@types/react": "^19.3.0",
65
- "@types/react-dom": "^19.3.0",
66
- "happy-dom": "^20.14.5",
67
- "lucide-react": "^1.52.0",
68
- "react": "^19.3.0",
69
- "react-dom": "^19.3.0",
70
- "react-router-dom": "^7.18.4",
71
- "typescript": "^7.0.2",
72
- "vite": "^8.3.2",
73
- "vitest": "^5.0.3",
74
- "zod": "^3.24.1"
75
- },
76
- "publishConfig": {
77
- "access": "public"
78
- }
79
- }
1
+ {
2
+ "name": "@llmnative/agentico",
3
+ "version": "0.4.0",
4
+ "description": "Agentic chat orchestrator for @llmnative/react apps: a persistent panel that talks with the user and hands the work to host-registered subagents.",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/types/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/types/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "llms.txt"
18
+ ],
19
+ "sideEffects": false,
20
+ "scripts": {
21
+ "build": "vite build && tsc -p tsconfig.build.json",
22
+ "typecheck": "tsc --noEmit",
23
+ "test": "vitest run",
24
+ "test:watch": "vitest",
25
+ "prepublishOnly": "npm run build",
26
+ "release:check": "node scripts/release/check-release.mjs"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/sherpadvisorylab/llmnative-agentico.git"
31
+ },
32
+ "bugs": {
33
+ "url": "https://github.com/sherpadvisorylab/llmnative-agentico/issues"
34
+ },
35
+ "homepage": "https://github.com/sherpadvisorylab/llmnative-agentico#readme",
36
+ "keywords": [
37
+ "llmnative",
38
+ "agent",
39
+ "orchestrator",
40
+ "subagent",
41
+ "ai",
42
+ "react"
43
+ ],
44
+ "author": "wolfgan",
45
+ "license": "Apache-2.0",
46
+ "engines": {
47
+ "node": ">=24.18.0 <25"
48
+ },
49
+ "packageManager": "npm@11.11.0",
50
+ "peerDependencies": {
51
+ "@llmnative/react": "^1.34.0",
52
+ "react": "^19.2.0",
53
+ "react-dom": "^19.2.0",
54
+ "zod": "^3.24.1"
55
+ },
56
+ "dependencies": {
57
+ "zod-to-json-schema": "^3.24.1"
58
+ },
59
+ "devDependencies": {
60
+ "@llmnative/react": "^1.34.0",
61
+ "@phosphor-icons/react": "^2.1.10",
62
+ "@testing-library/jest-dom": "^7.0.1",
63
+ "@testing-library/react": "^16.3.3",
64
+ "@types/react": "^19.3.0",
65
+ "@types/react-dom": "^19.3.0",
66
+ "happy-dom": "^20.14.5",
67
+ "lucide-react": "^1.52.0",
68
+ "react": "^19.3.0",
69
+ "react-dom": "^19.3.0",
70
+ "react-router-dom": "^7.18.4",
71
+ "typescript": "^7.0.2",
72
+ "vite": "^8.3.2",
73
+ "vitest": "^5.0.3",
74
+ "zod": "^3.24.1"
75
+ },
76
+ "publishConfig": {
77
+ "access": "public"
78
+ }
79
+ }