@livx.cc/agentx 0.99.105 → 0.99.107
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/README.md +2 -0
- package/dist/cli.d.ts +13 -5
- package/dist/cli.js +3549 -2672
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +202 -14
- package/dist/index.js +1712 -113
- package/dist/index.js.map +1 -1
- package/dist/{Agent-BhOcPaxG.d.ts → secondChannel-BYW5qPAJ.d.ts} +290 -1
- package/package.json +1 -1
|
@@ -771,4 +771,293 @@ declare class Agent {
|
|
|
771
771
|
* stub made `/compact` chase a target it could never reach and drop-oldest the conversation away. */
|
|
772
772
|
declare function estimateTokens(m: Message[], keepRecentImages?: number, vision?: boolean): number;
|
|
773
773
|
|
|
774
|
-
|
|
774
|
+
/** Structural subset of ai.libx.js DecideClient.decide — keeps this module provider-agnostic. */
|
|
775
|
+
interface Decider {
|
|
776
|
+
decide(o: {
|
|
777
|
+
state: unknown;
|
|
778
|
+
questions: Record<string, unknown>;
|
|
779
|
+
}): Promise<{
|
|
780
|
+
answers: Record<string, {
|
|
781
|
+
choice: string;
|
|
782
|
+
probabilities: Record<string, number>;
|
|
783
|
+
}>;
|
|
784
|
+
}>;
|
|
785
|
+
}
|
|
786
|
+
/** Duplex v2 second-channel actions (Instinct.channel's Choice). The silence bias lives in the CRITERIA, not prose: a
|
|
787
|
+
* greeting or a quick full turn the reflex answers at once scores `silence` (v1's failure: "hmm ok" after a bare "hey"). */
|
|
788
|
+
declare const CHANNEL_ACTIONS: {
|
|
789
|
+
readonly silence: "the default — nothing to add. ALWAYS for a greeting, thanks, a yes/no, or any short complete turn the real reply will answer instantly (\"hey\", \"how are you?\", \"thanks\"); also mid-word or mid-clause";
|
|
790
|
+
readonly backchannel: "they are mid-way through a longer story or explanation (several clauses) and just closed a clause: a tiny \"mm-hm\"/\"right\" shows you follow, without taking the turn";
|
|
791
|
+
readonly filler: "they paused mid-thought, searching for words, and a soft \"hmm\" keeps the line warm";
|
|
792
|
+
readonly bridge: "they finished a substantial request or hard question and the real answer takes a moment: a short \"let me check—\" lead-in";
|
|
793
|
+
};
|
|
794
|
+
type ChannelKind = keyof typeof CHANNEL_ACTIONS;
|
|
795
|
+
|
|
796
|
+
declare const TURN_TYPES: readonly ["story", "list", "complaint", "explanation", "short_command", "question", "other"];
|
|
797
|
+
type TurnType = typeof TURN_TYPES[number];
|
|
798
|
+
declare const DENSITIES: readonly ["none", "low", "normal", "high"];
|
|
799
|
+
type Density = typeof DENSITIES[number];
|
|
800
|
+
interface Cue {
|
|
801
|
+
when: string[];
|
|
802
|
+
line: string;
|
|
803
|
+
}
|
|
804
|
+
interface BcPlan {
|
|
805
|
+
turn: TurnType;
|
|
806
|
+
density: Density;
|
|
807
|
+
cues: Cue[];
|
|
808
|
+
}
|
|
809
|
+
/** The plan's micro-context — never history. */
|
|
810
|
+
interface PlanContext {
|
|
811
|
+
/** The agent's last reply (the user's next turn answers it). */
|
|
812
|
+
agent: string;
|
|
813
|
+
/** The tail of the user's previous turn. */
|
|
814
|
+
user: string;
|
|
815
|
+
/** Recent channel lines — not to be reused. */
|
|
816
|
+
recent: string[];
|
|
817
|
+
lang: string;
|
|
818
|
+
/** Revision only: what the user has said so far in this turn. */
|
|
819
|
+
heard?: string;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
type LineKind$1 = Exclude<ChannelKind, 'silence'>;
|
|
823
|
+
/** `phatic` = greeting/thanks/yes-no openers in this language: a short turn starting with one is answered by the reflex
|
|
824
|
+
* instantly, so the channel stays silent (never "hmm" after "hi"). Not a spoken kind. */
|
|
825
|
+
type Bank = Record<LineKind$1 | 'phatic', string[]>;
|
|
826
|
+
declare class ChannelBanksOptions {
|
|
827
|
+
/** Raw bank for a language (fastBankGenerator). Absent → English fallback only. */
|
|
828
|
+
generate?: (lang: string, avoid: string[], signal: AbortSignal) => Promise<unknown>;
|
|
829
|
+
/** Disk cache dir (one `<lang>.json` per language). Absent → in-memory only. */
|
|
830
|
+
cacheDir?: string;
|
|
831
|
+
/** A cached bank older than this is still used, and topped up by one background call. */
|
|
832
|
+
refreshMs: number;
|
|
833
|
+
/** Lines kept per kind (newest win) — the cap on growth. */
|
|
834
|
+
maxPerKind: number;
|
|
835
|
+
timeoutMs: number;
|
|
836
|
+
/** After a failed cold generation, the next attempt waits this long. */
|
|
837
|
+
retryMs: number;
|
|
838
|
+
/** Cold-start/offline banks (English only by default). */
|
|
839
|
+
fallback: Record<string, Bank>;
|
|
840
|
+
/** Hand-checked banks: used as-is for their language — never generated, cached or topped up. */
|
|
841
|
+
curated: Record<string, Bank>;
|
|
842
|
+
now: () => number;
|
|
843
|
+
}
|
|
844
|
+
declare class ChannelBanks {
|
|
845
|
+
options?: Partial<ChannelBanksOptions> | undefined;
|
|
846
|
+
private banks;
|
|
847
|
+
private pending;
|
|
848
|
+
constructor(options?: Partial<ChannelBanksOptions> | undefined);
|
|
849
|
+
private get o();
|
|
850
|
+
/** The bank to speak from for `lang` now — generated/cached, else the fallback, else null (= stay silent). */
|
|
851
|
+
get(lang: string): Bank | null;
|
|
852
|
+
/** Load (cache) and/or generate `lang`'s bank in the background. Never throws, never blocks the caller. */
|
|
853
|
+
ensure(lang: string): Promise<void>;
|
|
854
|
+
private file;
|
|
855
|
+
private load;
|
|
856
|
+
private generate;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
type LineKind = Exclude<ChannelKind, 'silence'>;
|
|
860
|
+
/** The main (channel-1) response lifecycle. `idle` = no turn in flight (the user has the floor). */
|
|
861
|
+
type MainState = 'idle' | 'queued' | 'thinking' | 'streaming_text' | 'first_audio' | 'speaking';
|
|
862
|
+
type Trigger = 'interim' | 'pause' | 'working';
|
|
863
|
+
/** The micro-context a generator gets: a tiny tail, never history. */
|
|
864
|
+
interface ChannelContext {
|
|
865
|
+
kind: LineKind;
|
|
866
|
+
/** The last ~microWords words the user said. */
|
|
867
|
+
heard: string;
|
|
868
|
+
state: MainState;
|
|
869
|
+
/** The last few channel lines — do not reuse. */
|
|
870
|
+
avoid: string[];
|
|
871
|
+
/** The user's language (BCP-47 primary code) — the line is written in it. */
|
|
872
|
+
lang: string;
|
|
873
|
+
/** A content reaction (chatty): "oh no", "wait, really?", a key-word echo — not just an "mm-hm". */
|
|
874
|
+
react?: boolean;
|
|
875
|
+
}
|
|
876
|
+
interface ChannelEvent {
|
|
877
|
+
trigger: Trigger;
|
|
878
|
+
rule: ChannelKind;
|
|
879
|
+
choice?: string;
|
|
880
|
+
acted: 'spoken' | 'silence' | 'stale' | 'gated' | 'skipped' | 'no_bank';
|
|
881
|
+
kind?: LineKind;
|
|
882
|
+
text?: string;
|
|
883
|
+
/** The backchannel came from a planned cue (anticipate) — its matched line. */
|
|
884
|
+
cue?: string;
|
|
885
|
+
ms: number;
|
|
886
|
+
}
|
|
887
|
+
/** How talkative the second channel is (`--channel-mode`). */
|
|
888
|
+
type ChannelMode = 'turn' | 'normal' | 'chatty';
|
|
889
|
+
declare class SecondChannelOptions {
|
|
890
|
+
/** Preset (CHANNEL_MODES) under the explicit options. */
|
|
891
|
+
mode: ChannelMode;
|
|
892
|
+
/** Line kinds this channel may speak. */
|
|
893
|
+
kinds: LineKind[];
|
|
894
|
+
/** A generated (content) backchannel needs this long since the last one; in between, canned light cues. 0 = always. */
|
|
895
|
+
reactionGapMs: number;
|
|
896
|
+
/** Refiner (Jev/fast LLM): the choice over CHANNEL_ACTIONS, or null on failure. Absent → the rule alone decides.
|
|
897
|
+
* `state.rule` is the kind the rule proposed (fastChannelDecider answers yes/no on it). `signal` aborts a late call. */
|
|
898
|
+
decide?: (heard: string, state: Record<string, unknown>, signal?: AbortSignal) => Promise<{
|
|
899
|
+
choice: string;
|
|
900
|
+
} | null>;
|
|
901
|
+
/** Fast-model line writer (see fastLineGenerator). Absent or late → the canned bank. */
|
|
902
|
+
generate?: (ctx: ChannelContext, signal: AbortSignal) => Promise<string>;
|
|
903
|
+
/** Per-language banks (ChannelBanks). Absent → the hardcoded English bank, and silence in any other language. */
|
|
904
|
+
banks?: Pick<ChannelBanks, 'get' | 'ensure'>;
|
|
905
|
+
/** The host's language (BCP-47; pinned — detection never overrides it). Absent → unknown until the user's words
|
|
906
|
+
* tell it confidently; the channel is silent until then (never English by default). */
|
|
907
|
+
lang?: string;
|
|
908
|
+
/** Kinds worth generating (content-conditioned); the rest are canned sounds. */
|
|
909
|
+
generateFor: LineKind[];
|
|
910
|
+
/** Host TTS on the second channel; resolves when the line finished playing. `false` = the host could not play it. */
|
|
911
|
+
speak: (text: string, kind: LineKind) => Promise<unknown> | boolean | void;
|
|
912
|
+
/** Host UI (caption / muted line) — never history. */
|
|
913
|
+
show: (text: string, kind: LineKind) => void;
|
|
914
|
+
/** Stop the in-flight line's audio now (barge-in only). */
|
|
915
|
+
cancel: () => void;
|
|
916
|
+
onEvent: (e: ChannelEvent) => void;
|
|
917
|
+
/** Echo cancellation on: backchannels may play while the user speaks. Off (half-duplex) → fillers/bridges in silences only. */
|
|
918
|
+
aec: boolean;
|
|
919
|
+
decideEveryWords: number;
|
|
920
|
+
decisionBudgetMs: number;
|
|
921
|
+
generateBudgetMs: number;
|
|
922
|
+
minGapMs: number;
|
|
923
|
+
/** Backchannel after backchannel needs this gap (~4-6 cues in a 30s monologue — Para phone call 2026-10-13: 5s left
|
|
924
|
+
* one cue in a long statement). */
|
|
925
|
+
backchannelGapMs: number;
|
|
926
|
+
/** Soft cap: at most this many backchannels in any `windowMs` (0 = none). */
|
|
927
|
+
maxPerWindow: number;
|
|
928
|
+
windowMs: number;
|
|
929
|
+
/** The user resumes within this long of their last words after a line of theirs was dispatched: the same statement goes
|
|
930
|
+
* on (an STT endpoint mid-monologue) — its words still count toward the backchannel guards, and it is no fresh request. */
|
|
931
|
+
continueMs: number;
|
|
932
|
+
/** A decision whose partial grew by this many words while in flight is stale → dropped. */
|
|
933
|
+
staleWords: number;
|
|
934
|
+
microWords: number;
|
|
935
|
+
avoidLines: number;
|
|
936
|
+
/** Canned picks exclude the last N picks of the same kind. */
|
|
937
|
+
bankExclude: number;
|
|
938
|
+
/** A backchannel needs a substantial chunk first: a turn of ≤8 words is a request/answer, not a story (replay: most
|
|
939
|
+
* misplaced "mm-hm"s fired at words 6-8 of a short command). */
|
|
940
|
+
backchannelMinWords: number;
|
|
941
|
+
/** A turn that opens as a question/command (requestOpener) holds backchannels until it has grown into an explanation. */
|
|
942
|
+
requestHoldWords: number;
|
|
943
|
+
/** No new interim for this long mid-utterance (a breath / clause gap, shorter than a pause) → a backchannel moment. */
|
|
944
|
+
backchannelPauseMs: number;
|
|
945
|
+
/** A bridge waits this long after the user's turn is dispatched, and plays only if channel-1 has said nothing yet
|
|
946
|
+
* (a fast reply/ack needs no bridge — one before it reads as the agent starting a different sentence). 0 = at once. */
|
|
947
|
+
bridgeDelayMs: number;
|
|
948
|
+
/** No new interim for this long → a pause (hosts may also call onPause). */
|
|
949
|
+
fillerPauseMs: number;
|
|
950
|
+
fillerMinWords: number;
|
|
951
|
+
bridgeMinWords: number;
|
|
952
|
+
/** ANTICIPATE (backchannelPlan.ts): plan the user's next turn off the hot path (after the agent's reply / at turn start,
|
|
953
|
+
* revised once at `reviseAtWords`); live, a backchannel fires only on a planned cue, at a `cuePauseMs` breath, with the
|
|
954
|
+
* cue's line and no decider call. A silent plan (short command / question / density none) vetoes backchannels. No plan
|
|
955
|
+
* yet / failed / late → the reactive path. Off by default (AGENTX_CHANNEL_ANTICIPATE=1). */
|
|
956
|
+
anticipate: boolean;
|
|
957
|
+
plan?: (ctx: PlanContext, signal: AbortSignal) => Promise<BcPlan | null>;
|
|
958
|
+
planBudgetMs: number;
|
|
959
|
+
reviseAtWords: number;
|
|
960
|
+
/** A predicted moment needs only a short breath (the decision is already made). */
|
|
961
|
+
cuePauseMs: number;
|
|
962
|
+
/** A cue counts only within the last N words (older matches were gated or passed). */
|
|
963
|
+
cueWindow: number;
|
|
964
|
+
/** true: a plan fires on its cues only. false: a non-silent plan with density normal/high also lets the reactive breath
|
|
965
|
+
* backchannel through (the plan then only vetoes short commands / questions / low density). */
|
|
966
|
+
cueOnly: boolean;
|
|
967
|
+
onPlan: (p: BcPlan, revised: boolean, ms: number) => void;
|
|
968
|
+
now: () => number;
|
|
969
|
+
random: () => number;
|
|
970
|
+
}
|
|
971
|
+
declare class SecondChannel {
|
|
972
|
+
options?: Partial<SecondChannelOptions> | undefined;
|
|
973
|
+
private heard;
|
|
974
|
+
private userSpeaking;
|
|
975
|
+
private main;
|
|
976
|
+
private gen;
|
|
977
|
+
private decidedAt;
|
|
978
|
+
private busy;
|
|
979
|
+
private pauseTimer;
|
|
980
|
+
private bcTimer;
|
|
981
|
+
private bridgeTimer;
|
|
982
|
+
private lastAt;
|
|
983
|
+
private lastKind;
|
|
984
|
+
private live;
|
|
985
|
+
private cutLine;
|
|
986
|
+
private bridged;
|
|
987
|
+
private recent;
|
|
988
|
+
private picks;
|
|
989
|
+
private inflight;
|
|
990
|
+
private readonly startedAt;
|
|
991
|
+
private lang;
|
|
992
|
+
private carried;
|
|
993
|
+
private floorWords;
|
|
994
|
+
private lastHeardAt;
|
|
995
|
+
private pinned;
|
|
996
|
+
private turnNo;
|
|
997
|
+
private plan;
|
|
998
|
+
private planning;
|
|
999
|
+
private planTries;
|
|
1000
|
+
private revised;
|
|
1001
|
+
private cueFrom;
|
|
1002
|
+
private reply;
|
|
1003
|
+
private lastUser;
|
|
1004
|
+
private lastReactAt;
|
|
1005
|
+
private normalTiming;
|
|
1006
|
+
private degradedLogged;
|
|
1007
|
+
constructor(options?: Partial<SecondChannelOptions> | undefined);
|
|
1008
|
+
/** The language lines are spoken in (detected from the user's words, or set by the host). */
|
|
1009
|
+
get language(): string | null;
|
|
1010
|
+
/** Switch language: its bank starts loading in the background. `host` = the host's STT-reported language — it pins
|
|
1011
|
+
* the language (later detection never overrides it; only another host call does). Tags normalize to 'he-IL' → 'he'. */
|
|
1012
|
+
setLanguage(tag: string, host?: boolean): void;
|
|
1013
|
+
/** Once a language is known, switching needs strong evidence (detectLanguage's `switching`): an English "Um," read as
|
|
1014
|
+
* Portuguese flipped a live session to pt (silence until a pt bank was generated — it then spoke Portuguese). */
|
|
1015
|
+
private detect;
|
|
1016
|
+
private get bank();
|
|
1017
|
+
private get o();
|
|
1018
|
+
/** The user's live partial for the current turn (the whole partial, not a delta). */
|
|
1019
|
+
onInterim(text: string): void;
|
|
1020
|
+
/** The user went quiet for `ms` (host VAD/STT pause, or the internal interim timer). */
|
|
1021
|
+
onPause(ms: number): void;
|
|
1022
|
+
/** Channel-1 lifecycle. `queued` = the user's turn was dispatched to the main agent. */
|
|
1023
|
+
onAgentState(s: MainState): void;
|
|
1024
|
+
/** The user's final line was dispatched to the main agent (its words are the bridge's micro-context). */
|
|
1025
|
+
onUserTurn(text: string): void;
|
|
1026
|
+
/** The main answer's streamed text (before its audio): channel-1 is responding — no bridge from here on. */
|
|
1027
|
+
onMainTokens(text: string): void;
|
|
1028
|
+
/** Channel-1's reply text (a delta) — only the plan's context; no state change (hosts without onMainTokens). */
|
|
1029
|
+
noteReply(text: string): void;
|
|
1030
|
+
/** The user barged in: cut the in-flight line now and drop every pending decision. */
|
|
1031
|
+
onBargeIn(): void;
|
|
1032
|
+
/** Is `text` the line the last barge-in cut (ours, still holding the floor)? Hosts strip it from the cut reply — it is
|
|
1033
|
+
* not the agent's speech. By identity, not by text: a real reply that merely repeats a recent line is kept. Consumed once. */
|
|
1034
|
+
spoke(text: string): boolean;
|
|
1035
|
+
/** Resolves when the in-flight line finished playing (immediately when none) — hosts enqueue channel-1 audio behind it. */
|
|
1036
|
+
drain(): Promise<void>;
|
|
1037
|
+
/** Channel-1's last reply ended on a CLOSED question (yes/no, "X or Y?", a confirm): the user's current turn answers or
|
|
1038
|
+
* corrects it. An open invitation ("what happened?") is different — a story follows, and reactions fit it. */
|
|
1039
|
+
private get answeringUs();
|
|
1040
|
+
private get audioLocked();
|
|
1041
|
+
private tail;
|
|
1042
|
+
/** Hard gates every line passes, whoever proposed it. */
|
|
1043
|
+
private allowed;
|
|
1044
|
+
private bcTimes;
|
|
1045
|
+
private capped;
|
|
1046
|
+
/** 0ms rule: the candidate line for this trigger, or silence. */
|
|
1047
|
+
private rule;
|
|
1048
|
+
/** Plan (or, with `heard`, revise) the backchannels of the user's turn — async, never on the hot path. */
|
|
1049
|
+
private requestPlan;
|
|
1050
|
+
/** A clause boundary mid-floor: a breath or a comma-like close. Not a question (it wants the answer, not "mm-hm"), and a
|
|
1051
|
+
* sentence end only deep into a story — a short request's end is the end of their turn (replay: "mm-hm" right after
|
|
1052
|
+
* "Check hacker news for recent news.", just before the final). */
|
|
1053
|
+
private backchannelMoment;
|
|
1054
|
+
private consider;
|
|
1055
|
+
private state;
|
|
1056
|
+
private line;
|
|
1057
|
+
/** Canned rotation in the user's language: never one of the last `bankExclude` picks of this kind, nor a recent
|
|
1058
|
+
* line. '' = no bank for this language yet (silence). */
|
|
1059
|
+
private pick;
|
|
1060
|
+
private say;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
export { Agent as A, reasoningToChatFragment as B, type ChannelMode as C, DEFAULT_MUTATING as D, type Hooks as H, type LineKind as L, ModelRouter as M, PermissionOptions as P, type ReasoningEffort as R, SecondChannel as S, type Tier as T, AgentOptions as a, type ChatFragment as b, type Classification as c, type Classifier as d, type CompactResult as e, type Decider as f, type Decision as g, ModelRouterOptions as h, PermissionPolicy as i, type PermissionRule as j, type PreToolUseDecision as k, RecordingHooks as l, RecordingLifecycle as m, type RouteDecision as n, type RouterState as o, type RunResult as p, SecondChannelOptions as q, type ToolUse as r, type ToolUseMeta as s, claudeCodeDisallowedTools as t, composeHooks as u, estimateTokens as v, jevAvailable as w, jevClassifier as x, pickTier as y, planMode as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livx.cc/agentx",
|
|
3
|
-
"version": "0.99.
|
|
3
|
+
"version": "0.99.107",
|
|
4
4
|
"description": "Edge-native AI agent runtime — drives a virtual filesystem via any LLM (ai.libx.js). Same bytes run in node, browser, or edge.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|