@fungi.computer/parakeet 0.1.0 → 0.2.1
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 +45 -6
- package/dist/account-commands.js +3 -11
- package/dist/commands/advertised.d.ts +3 -1
- package/dist/commands/advertised.js +89 -4
- package/dist/commands/interactions.d.ts +22 -7
- package/dist/commands/interactions.js +41 -17
- package/dist/commands/slash.js +3 -5
- package/dist/commands/use-slash-commands.js +2 -2
- package/dist/components/AgentHead.d.ts +2 -0
- package/dist/components/AgentHead.js +5 -4
- package/dist/components/ChatComposer.d.ts +3 -1
- package/dist/components/ChatComposer.js +79 -15
- package/dist/components/ChatMessage.d.ts +4 -0
- package/dist/components/ChatMessage.js +6 -2
- package/dist/components/ClientRows.js +2 -2
- package/dist/components/InteractionPanel.d.ts +2 -4
- package/dist/components/InteractionPanel.js +2 -2
- package/dist/components/TimelineItem.d.ts +2 -0
- package/dist/components/TimelineItem.js +31 -7
- package/dist/conversation-opening.d.ts +47 -0
- package/dist/conversation-opening.js +173 -0
- package/dist/conversation.d.ts +47 -3
- package/dist/conversation.js +584 -86
- package/dist/core/author-labels.d.ts +2 -0
- package/dist/core/build-timeline.d.ts +4 -2
- package/dist/core/build-timeline.js +46 -7
- package/dist/core/client-actions.js +6 -3
- package/dist/core/client-timeline.d.ts +9 -2
- package/dist/core/client-timeline.js +15 -4
- package/dist/core/draft-storage.d.ts +63 -0
- package/dist/core/draft-storage.js +50 -0
- package/dist/core/model-identity.d.ts +2 -0
- package/dist/core/model-identity.js +6 -0
- package/dist/core/queued-recall.d.ts +35 -0
- package/dist/core/queued-recall.js +138 -0
- package/dist/core/session-projection.js +17 -0
- package/dist/core/session-query.d.ts +54 -11
- package/dist/core/session-query.js +38 -12
- package/dist/core/tool-groups.d.ts +1 -1
- package/dist/core/tool-groups.js +3 -1
- package/dist/core/tool-view.js +2 -1
- package/dist/core/use-timeline-item-key.d.ts +8 -0
- package/dist/core/use-timeline-item-key.js +29 -0
- package/dist/headless.d.ts +6 -4
- package/dist/headless.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/model-commands.js +64 -39
- package/dist/parakeet.js +17 -18
- package/dist/session-commands.d.ts +0 -9
- package/dist/session-commands.js +39 -68
- package/dist/session.d.ts +1 -1
- package/dist/store/types.d.ts +10 -4
- package/dist/styles.css +27 -12
- package/docs/api/commands/slash.md +24 -21
- package/docs/api/headless.md +375 -232
- package/docs/api/index.md +157 -45
- package/package.json +16 -10
- package/src/styles.css +0 -9
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SessionSnapshot } from "@fungi.computer/shiitake/client";
|
|
1
|
+
import type { SessionSnapshot, PromptCommand } from "@fungi.computer/shiitake/client";
|
|
2
2
|
import { type QueryClient } from "@tanstack/react-query";
|
|
3
3
|
import type { ParakeetSession } from "../session.js";
|
|
4
4
|
/** One shared TanStack observation keyed by Shiitake's logical Session address. */
|
|
@@ -7,36 +7,75 @@ export declare function sessionQueryOptions(session: ParakeetSession): import("@
|
|
|
7
7
|
observation: "connecting" | "live";
|
|
8
8
|
/** Last coherent durable Session state, absent before the first snapshot. */
|
|
9
9
|
snapshot: SessionSnapshot | undefined;
|
|
10
|
-
/** One retryable user prompt survives
|
|
11
|
-
latestPrompt:
|
|
10
|
+
/** One retryable user prompt, including image cargo, survives page refreshes. */
|
|
11
|
+
latestPrompt: Readonly<{
|
|
12
|
+
/** Owner-issued identity of the original prompt command. */
|
|
13
|
+
commandId: string;
|
|
14
|
+
/** Original user text, including an empty image-only prompt body. */
|
|
15
|
+
text: string;
|
|
16
|
+
/** Original image content retained for a fresh retry admission. */
|
|
17
|
+
images: PromptCommand["images"];
|
|
18
|
+
}> | undefined;
|
|
12
19
|
}>, Error, Readonly<{
|
|
13
20
|
/** Whether the current watch has supplied a fresh owner baseline. */
|
|
14
21
|
observation: "connecting" | "live";
|
|
15
22
|
/** Last coherent durable Session state, absent before the first snapshot. */
|
|
16
23
|
snapshot: SessionSnapshot | undefined;
|
|
17
|
-
/** One retryable user prompt survives
|
|
18
|
-
latestPrompt:
|
|
24
|
+
/** One retryable user prompt, including image cargo, survives page refreshes. */
|
|
25
|
+
latestPrompt: Readonly<{
|
|
26
|
+
/** Owner-issued identity of the original prompt command. */
|
|
27
|
+
commandId: string;
|
|
28
|
+
/** Original user text, including an empty image-only prompt body. */
|
|
29
|
+
text: string;
|
|
30
|
+
/** Original image content retained for a fresh retry admission. */
|
|
31
|
+
images: PromptCommand["images"];
|
|
32
|
+
}> | undefined;
|
|
19
33
|
}>, readonly ["shiitake-session", string]>, "queryFn"> & {
|
|
20
34
|
queryFn?: import("@tanstack/react-query").QueryFunction<Readonly<{
|
|
21
35
|
/** Whether the current watch has supplied a fresh owner baseline. */
|
|
22
36
|
observation: "connecting" | "live";
|
|
23
37
|
/** Last coherent durable Session state, absent before the first snapshot. */
|
|
24
38
|
snapshot: SessionSnapshot | undefined;
|
|
25
|
-
/** One retryable user prompt survives
|
|
26
|
-
latestPrompt:
|
|
39
|
+
/** One retryable user prompt, including image cargo, survives page refreshes. */
|
|
40
|
+
latestPrompt: Readonly<{
|
|
41
|
+
/** Owner-issued identity of the original prompt command. */
|
|
42
|
+
commandId: string;
|
|
43
|
+
/** Original user text, including an empty image-only prompt body. */
|
|
44
|
+
text: string;
|
|
45
|
+
/** Original image content retained for a fresh retry admission. */
|
|
46
|
+
images: PromptCommand["images"];
|
|
47
|
+
}> | undefined;
|
|
27
48
|
}>, readonly ["shiitake-session", string], never>;
|
|
28
49
|
} & import("@tanstack/react-query").QueryKeyWithDataTag<readonly ["shiitake-session", string], Readonly<{
|
|
29
50
|
/** Whether the current watch has supplied a fresh owner baseline. */
|
|
30
51
|
observation: "connecting" | "live";
|
|
31
52
|
/** Last coherent durable Session state, absent before the first snapshot. */
|
|
32
53
|
snapshot: SessionSnapshot | undefined;
|
|
33
|
-
/** One retryable user prompt survives
|
|
34
|
-
latestPrompt:
|
|
54
|
+
/** One retryable user prompt, including image cargo, survives page refreshes. */
|
|
55
|
+
latestPrompt: Readonly<{
|
|
56
|
+
/** Owner-issued identity of the original prompt command. */
|
|
57
|
+
commandId: string;
|
|
58
|
+
/** Original user text, including an empty image-only prompt body. */
|
|
59
|
+
text: string;
|
|
60
|
+
/** Original image content retained for a fresh retry admission. */
|
|
61
|
+
images: PromptCommand["images"];
|
|
62
|
+
}> | undefined;
|
|
35
63
|
}>, Error>;
|
|
36
64
|
/** Seed the shared observation with a bounded read before its watch mounts. */
|
|
37
65
|
export declare function seedSessionQuery(queryClient: QueryClient, session: ParakeetSession, snapshot: SessionSnapshot): void;
|
|
38
|
-
/**
|
|
39
|
-
export
|
|
66
|
+
/** Observed Session activity; `header` is only an attention item's short heading. */
|
|
67
|
+
export type SessionActivity = Readonly<{
|
|
68
|
+
/** The Session's observed activity. */
|
|
69
|
+
state: "idle" | "working" | "blocked" | "unknown";
|
|
70
|
+
/** Present when blocked by attention items: their short headings only. */
|
|
71
|
+
header?: string;
|
|
72
|
+
}>;
|
|
73
|
+
/**
|
|
74
|
+
* Borrow activity from the existing cache without starting another watch.
|
|
75
|
+
* An open attention item (such as an unanswered question) reports `blocked`
|
|
76
|
+
* ahead of working and idle; the header comes only from the question extension.
|
|
77
|
+
*/
|
|
78
|
+
export declare function subscribeSessionActivity(queryClient: QueryClient, session: ParakeetSession, listener: (activity: SessionActivity) => void, questionExtensionId: string | undefined): () => void;
|
|
40
79
|
/** Shared, demand-loaded history; the live watch remains a separate small tail. */
|
|
41
80
|
export declare function sessionHistoryQueryOptions(session: ParakeetSession, before?: string | null): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseInfiniteQueryOptions<Readonly<{
|
|
42
81
|
sessionId: string;
|
|
@@ -51,6 +90,7 @@ export declare function sessionHistoryQueryOptions(session: ParakeetSession, bef
|
|
|
51
90
|
pending: import("@fungi.computer/shiitake/client").SessionPendingPrompts;
|
|
52
91
|
activity: import("@fungi.computer/shiitake/client").SessionActivity;
|
|
53
92
|
progress: import("@fungi.computer/shiitake/client").SessionProgress | null;
|
|
93
|
+
toolOutput: readonly import("@fungi.computer/shiitake/client").SessionToolOutput[];
|
|
54
94
|
extensions: import("@fungi.computer/shiitake/client").SessionExtensionSlots;
|
|
55
95
|
attention: readonly import("@fungi.computer/shiitake/client").SessionAttention[];
|
|
56
96
|
context?: import("@fungi.computer/shiitake/client").SessionContext;
|
|
@@ -68,6 +108,7 @@ export declare function sessionHistoryQueryOptions(session: ParakeetSession, bef
|
|
|
68
108
|
pending: import("@fungi.computer/shiitake/client").SessionPendingPrompts;
|
|
69
109
|
activity: import("@fungi.computer/shiitake/client").SessionActivity;
|
|
70
110
|
progress: import("@fungi.computer/shiitake/client").SessionProgress | null;
|
|
111
|
+
toolOutput: readonly import("@fungi.computer/shiitake/client").SessionToolOutput[];
|
|
71
112
|
extensions: import("@fungi.computer/shiitake/client").SessionExtensionSlots;
|
|
72
113
|
attention: readonly import("@fungi.computer/shiitake/client").SessionAttention[];
|
|
73
114
|
context?: import("@fungi.computer/shiitake/client").SessionContext;
|
|
@@ -91,6 +132,7 @@ export declare function sessionHistoryQueryOptions(session: ParakeetSession, bef
|
|
|
91
132
|
pending: import("@fungi.computer/shiitake/client").SessionPendingPrompts;
|
|
92
133
|
activity: import("@fungi.computer/shiitake/client").SessionActivity;
|
|
93
134
|
progress: import("@fungi.computer/shiitake/client").SessionProgress | null;
|
|
135
|
+
toolOutput: readonly import("@fungi.computer/shiitake/client").SessionToolOutput[];
|
|
94
136
|
extensions: import("@fungi.computer/shiitake/client").SessionExtensionSlots;
|
|
95
137
|
attention: readonly import("@fungi.computer/shiitake/client").SessionAttention[];
|
|
96
138
|
context?: import("@fungi.computer/shiitake/client").SessionContext;
|
|
@@ -112,6 +154,7 @@ export declare function sessionHistoryQueryOptions(session: ParakeetSession, bef
|
|
|
112
154
|
pending: import("@fungi.computer/shiitake/client").SessionPendingPrompts;
|
|
113
155
|
activity: import("@fungi.computer/shiitake/client").SessionActivity;
|
|
114
156
|
progress: import("@fungi.computer/shiitake/client").SessionProgress | null;
|
|
157
|
+
toolOutput: readonly import("@fungi.computer/shiitake/client").SessionToolOutput[];
|
|
115
158
|
extensions: import("@fungi.computer/shiitake/client").SessionExtensionSlots;
|
|
116
159
|
attention: readonly import("@fungi.computer/shiitake/client").SessionAttention[];
|
|
117
160
|
context?: import("@fungi.computer/shiitake/client").SessionContext;
|
|
@@ -13,9 +13,8 @@ const emptyProjection = Object.freeze({
|
|
|
13
13
|
const LIVE_HISTORY_LIMIT = 200;
|
|
14
14
|
const LIVE_HISTORY_REFRESH_AT = 400;
|
|
15
15
|
function latestPrompt(messages, previous) {
|
|
16
|
-
for (
|
|
17
|
-
|
|
18
|
-
if (message?.value.role !== "user" || message.commandId === null)
|
|
16
|
+
for (const message of messages.slice().reverse()) {
|
|
17
|
+
if (message.value.role !== "user" || message.commandId === null)
|
|
19
18
|
continue;
|
|
20
19
|
const content = message.value.content;
|
|
21
20
|
const text = Array.isArray(content)
|
|
@@ -23,7 +22,14 @@ function latestPrompt(messages, previous) {
|
|
|
23
22
|
.flatMap((part) => (part.type === "text" ? [part.text] : []))
|
|
24
23
|
.join("\n")
|
|
25
24
|
: content;
|
|
26
|
-
|
|
25
|
+
const images = Array.isArray(content)
|
|
26
|
+
? content.filter((part) => part.type === "image")
|
|
27
|
+
: [];
|
|
28
|
+
return {
|
|
29
|
+
commandId: message.commandId,
|
|
30
|
+
text,
|
|
31
|
+
images: images.length === 0 ? undefined : images,
|
|
32
|
+
};
|
|
27
33
|
}
|
|
28
34
|
return previous;
|
|
29
35
|
}
|
|
@@ -116,21 +122,41 @@ export function seedSessionQuery(queryClient, session, snapshot) {
|
|
|
116
122
|
latestPrompt: latestPrompt(snapshot.messages),
|
|
117
123
|
});
|
|
118
124
|
}
|
|
119
|
-
/**
|
|
120
|
-
|
|
125
|
+
/** Longest header a Session activity may carry. */
|
|
126
|
+
const maximumActivityHeader = 80;
|
|
127
|
+
/**
|
|
128
|
+
* Borrow activity from the existing cache without starting another watch.
|
|
129
|
+
* An open attention item (such as an unanswered question) reports `blocked`
|
|
130
|
+
* ahead of working and idle; the header comes only from the question extension.
|
|
131
|
+
*/
|
|
132
|
+
export function subscribeSessionActivity(queryClient, session, listener, questionExtensionId) {
|
|
121
133
|
const observer = new QueryObserver(queryClient, {
|
|
122
134
|
...sessionQueryOptions(session),
|
|
123
135
|
enabled: false,
|
|
124
136
|
});
|
|
125
137
|
const report = (result) => {
|
|
126
138
|
const snapshot = result.data?.snapshot;
|
|
127
|
-
|
|
139
|
+
if (result.isError ||
|
|
128
140
|
result.data?.observation !== "live" ||
|
|
129
|
-
snapshot === undefined
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
141
|
+
snapshot === undefined)
|
|
142
|
+
listener({ state: "unknown" });
|
|
143
|
+
else if (snapshot.attention.some((item) => item.kind === "question" ||
|
|
144
|
+
item.kind === "goal-blocked" ||
|
|
145
|
+
item.kind === "goal-stalled")) {
|
|
146
|
+
// Only the question owner's short headers may leave the Session.
|
|
147
|
+
const header = snapshot.attention
|
|
148
|
+
.filter((item) => questionExtensionId !== undefined &&
|
|
149
|
+
item.kind === "question" &&
|
|
150
|
+
item.extensionId === questionExtensionId)
|
|
151
|
+
.map((item) => item.summary)
|
|
152
|
+
.join(", ")
|
|
153
|
+
.slice(0, maximumActivityHeader);
|
|
154
|
+
listener(header === "" ? { state: "blocked" } : { state: "blocked", header });
|
|
155
|
+
}
|
|
156
|
+
else
|
|
157
|
+
listener({
|
|
158
|
+
state: snapshot.activity.queue.state === "idle" ? "idle" : "working",
|
|
159
|
+
});
|
|
134
160
|
};
|
|
135
161
|
const unsubscribe = observer.subscribe(report);
|
|
136
162
|
report(observer.getCurrentResult());
|
|
@@ -6,7 +6,7 @@ export declare function toolGroup(tools: readonly [ToolItem, ...ToolItem[]]): To
|
|
|
6
6
|
* Fold a stretch of tool work into one group. User rows and rendered assistant
|
|
7
7
|
* content end the stretch; invisible assistant rows can span it.
|
|
8
8
|
*/
|
|
9
|
-
export declare function groupToolCalls(items: readonly ProjectedItem[]): TimelineItem[];
|
|
9
|
+
export declare function groupToolCalls(items: readonly ProjectedItem[], breakBefore?: ReadonlySet<string>): TimelineItem[];
|
|
10
10
|
/** View-only open/closed state shared by the browser and terminal renderers. */
|
|
11
11
|
export type ToolDisclosureState = Readonly<{
|
|
12
12
|
/**
|
package/dist/core/tool-groups.js
CHANGED
|
@@ -76,7 +76,7 @@ export function toolGroup(tools) {
|
|
|
76
76
|
* Fold a stretch of tool work into one group. User rows and rendered assistant
|
|
77
77
|
* content end the stretch; invisible assistant rows can span it.
|
|
78
78
|
*/
|
|
79
|
-
export function groupToolCalls(items) {
|
|
79
|
+
export function groupToolCalls(items, breakBefore = new Set()) {
|
|
80
80
|
const rows = [];
|
|
81
81
|
let run = [];
|
|
82
82
|
let nontextRows = [];
|
|
@@ -89,6 +89,8 @@ export function groupToolCalls(items) {
|
|
|
89
89
|
nontextRows = [];
|
|
90
90
|
};
|
|
91
91
|
for (const item of items) {
|
|
92
|
+
if (breakBefore.has(item.id))
|
|
93
|
+
flush();
|
|
92
94
|
if (item.kind === "tool") {
|
|
93
95
|
run.push(item);
|
|
94
96
|
continue;
|
package/dist/core/tool-view.js
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TimelineItem } from "../store/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The virtualizer's row-key callback. Text-only progress replaces tail items
|
|
4
|
+
* but not their keys, so the callback keeps its identity, and the virtualizer
|
|
5
|
+
* its measurements, until the settled history or the order or identity of the
|
|
6
|
+
* tail rows changes. Settled rows are keyed from the settled list alone.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useTimelineItemKey(settled: readonly TimelineItem[], tail: readonly TimelineItem[]): (index: number) => string | number;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useCallback, useState } from "react";
|
|
2
|
+
/** One submitted prompt keeps one row from submit to durable: no remount. */
|
|
3
|
+
function rowKey(item) {
|
|
4
|
+
return item.kind === "user_message" && item.requestId !== undefined
|
|
5
|
+
? item.requestId
|
|
6
|
+
: item.id;
|
|
7
|
+
}
|
|
8
|
+
function sameKeys(a, b) {
|
|
9
|
+
return a.length === b.length && a.every((key, index) => key === b[index]);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The virtualizer's row-key callback. Text-only progress replaces tail items
|
|
13
|
+
* but not their keys, so the callback keeps its identity, and the virtualizer
|
|
14
|
+
* its measurements, until the settled history or the order or identity of the
|
|
15
|
+
* tail rows changes. Settled rows are keyed from the settled list alone.
|
|
16
|
+
*/
|
|
17
|
+
export function useTimelineItemKey(settled, tail) {
|
|
18
|
+
const next = tail.map(rowKey);
|
|
19
|
+
const [previous, setPrevious] = useState(next);
|
|
20
|
+
const tailKeys = sameKeys(previous, next) ? previous : next;
|
|
21
|
+
if (tailKeys !== previous)
|
|
22
|
+
setPrevious(tailKeys);
|
|
23
|
+
return useCallback((index) => {
|
|
24
|
+
const item = settled[index];
|
|
25
|
+
if (item !== undefined)
|
|
26
|
+
return rowKey(item);
|
|
27
|
+
return tailKeys[index - settled.length] ?? index;
|
|
28
|
+
}, [settled, tailKeys]);
|
|
29
|
+
}
|
package/dist/headless.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
export { formatModelIdentity } from "./core/model-identity.js";
|
|
1
|
+
export { formatModelIdentity, formatModelWithLevel, } from "./core/model-identity.js";
|
|
2
|
+
export type { QueuedRecallState, QueuedRecallOutcome, } from "./core/queued-recall.js";
|
|
3
|
+
export type { ParakeetDraftIdentity, ParakeetDraftStorage, } from "./core/draft-storage.js";
|
|
2
4
|
export { formatContextUsage, formatTokenCount } from "./core/format-context.js";
|
|
3
5
|
export { providerChoices } from "./provider-choices.js";
|
|
4
|
-
export { ParakeetProvider, useComposer, useClientContributions, useParakeetInteractions, useExtensionSlots, useParakeetSession, useStatus, useTimeline, type ComposerController, type ParakeetModel, type ParakeetObservation, type ParakeetReconnectOutcome, type ParakeetStatus, type ParakeetSessionViewState, type ParakeetUsage, type StatusController, type TimelineController, } from "./conversation.js";
|
|
6
|
+
export { ParakeetProvider, useComposer, useClientContributions, useParakeetInteractions, useExtensionSlots, useParakeetSession, useStatus, useTimeline, type ComposerController, type ParakeetDraftCheckpoint, type ParakeetModel, type ParakeetObservation, type ParakeetReconnectOutcome, type ParakeetStatus, type ParakeetSessionViewState, type ParakeetUsage, type StatusController, type TimelineController, } from "./conversation.js";
|
|
5
7
|
export { sessionViewState, queuedSessionLabel, sessionActivityStatus, type SessionActivityStatus, type SessionViewFacts, type SessionViewState as ParakeetOwnerViewState, } from "./core/session-view-state.js";
|
|
6
8
|
export { mergeTerminals } from "./core/session-projection.js";
|
|
7
|
-
export { seedSessionQuery, sessionQueryOptions, subscribeSessionActivity, } from "./core/session-query.js";
|
|
9
|
+
export { type SessionActivity, seedSessionQuery, sessionQueryOptions, subscribeSessionActivity, } from "./core/session-query.js";
|
|
8
10
|
export { accountCommandDefinitions, contributeAccountCommands, loginRegistry, type AccountCommandOptions, type AccountOwner, type ProviderAccess, type ModelAccountContext, type LoginHost, type LoginMethod, type LoginMethodKind, type LoginPolicy, type LoginProvider, type LoginScope, } from "./account-commands.js";
|
|
9
11
|
export { contributeModelCommands, sessionModelCommandDefinitions, type SessionModelChoice, type SessionModelCommandOptions, } from "./model-commands.js";
|
|
10
12
|
export { contributeReloadCommand, reloadCommandDefinitions, reloadSources, type ReloadCommandOptions, type ReloadSource, } from "./reload-command.js";
|
|
@@ -12,7 +14,7 @@ export { contributeSessionCommands, type ParakeetSessionCommandOptions, } from "
|
|
|
12
14
|
export { completeSlash, fuzzyMatch, keyBindings, keyLabel, parseSlashDraft, slashRegistry, type FuzzyMatch, type KeyBindingRow, type SlashCommand, type SlashCommandItem, type SlashCompletion, type SlashParse, type SlashWordItem, } from "./commands/slash.js";
|
|
13
15
|
export { composerHints, fitHints, formatHints, type ComposerHintContext, type ComposerKeys, type KeyHint, } from "./commands/hints.js";
|
|
14
16
|
export { isCancelledOutcome, runSlashDraft, type SlashRuntime, } from "./commands/run.js";
|
|
15
|
-
export { createParakeetInteractions, type ParakeetInteractions, type ParakeetInteractionState, type ParakeetNotice, type ParakeetOpenInteraction, } from "./commands/interactions.js";
|
|
17
|
+
export { createParakeetInteractions, type ParakeetInteractions, type ParakeetInteractionState, type ParakeetNotice, type ParakeetOpenInteraction, type ParakeetToast, } from "./commands/interactions.js";
|
|
16
18
|
export { parakeetBuiltinCommands, type ParakeetBuiltinOptions, } from "./commands/builtins.js";
|
|
17
19
|
export { advertisedCommands, type AdvertisedCatalogError, type AdvertisedCommands, } from "./commands/advertised.js";
|
|
18
20
|
export { useSlashCommands, type ParakeetCommandRuntime, type SlashCommandController, type SlashCommandOptions, } from "./commands/use-slash-commands.js";
|
package/dist/headless.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { formatModelIdentity } from "./core/model-identity.js";
|
|
1
|
+
export { formatModelIdentity, formatModelWithLevel, } from "./core/model-identity.js";
|
|
2
2
|
export { formatContextUsage, formatTokenCount } from "./core/format-context.js";
|
|
3
3
|
export { providerChoices } from "./provider-choices.js";
|
|
4
4
|
export { ParakeetProvider, useComposer, useClientContributions, useParakeetInteractions, useExtensionSlots, useParakeetSession, useStatus, useTimeline, } from "./conversation.js";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { ParakeetProvider, useComposer, useStatus, useTimeline, useMarkdown, disclosureOpen, formatToolDuration, formatModelIdentity, formatContextUsage, formatTokenCount, initialToolDisclosure, toggleAllDisclosure, toggleDisclosure, toolCallDefaultOpen, toolGroupDefaultOpen, visibleToolCalls, } from "./headless.js";
|
|
1
|
+
export { ParakeetProvider, useComposer, useStatus, useTimeline, useMarkdown, disclosureOpen, formatToolDuration, formatModelIdentity, formatModelWithLevel, formatContextUsage, formatTokenCount, initialToolDisclosure, toggleAllDisclosure, toggleDisclosure, toolCallDefaultOpen, toolGroupDefaultOpen, visibleToolCalls, } from "./headless.js";
|
|
2
2
|
export { Parakeet, ParakeetView } from "./parakeet.js";
|
|
3
3
|
export type { ParakeetVisitor } from "./parakeet.js";
|
|
4
4
|
export { InteractionPanel, type InteractionPanelProps, } from "./components/InteractionPanel.js";
|
|
5
|
-
export type { ParakeetAssistantMessageItem, ComposerController, ParakeetModel, ParakeetSession, ParakeetStatus, ParakeetTimelineItem, ParakeetToolArguments, ParakeetToolCallSection, ParakeetToolCallView, ParakeetToolDiffFile, ParakeetToolDiffHunk, ParakeetToolDiffLine, ParakeetToolDiffRow, ParakeetToolExcerptLine, ParakeetToolMatch, ParakeetToolOutputLine, ParakeetToolGroupItem, ParakeetToolItem, ParakeetToolKind, ToolDisclosureState, ParakeetUsage, ParakeetUserMessageItem, StatusController, TimelineController, MarkdownBlock, MarkdownInline, } from "./headless.js";
|
|
5
|
+
export type { QueuedRecallState, QueuedRecallOutcome, ParakeetAssistantMessageItem, ComposerController, ParakeetDraftCheckpoint, ParakeetDraftIdentity, ParakeetDraftStorage, ParakeetModel, ParakeetSession, ParakeetStatus, ParakeetTimelineItem, ParakeetToolArguments, ParakeetToolCallSection, ParakeetToolCallView, ParakeetToolDiffFile, ParakeetToolDiffHunk, ParakeetToolDiffLine, ParakeetToolDiffRow, ParakeetToolExcerptLine, ParakeetToolMatch, ParakeetToolOutputLine, ParakeetToolGroupItem, ParakeetToolItem, ParakeetToolKind, ToolDisclosureState, ParakeetUsage, ParakeetUserMessageItem, StatusController, TimelineController, MarkdownBlock, MarkdownInline, } from "./headless.js";
|
|
6
6
|
export type { ParakeetProps, ParakeetViewProps } from "./parakeet.js";
|
|
7
7
|
export type { ParakeetAuthor, ParakeetAuthorOf } from "./core/author-labels.js";
|
|
8
8
|
export type { ParakeetSessionCommand, ParakeetPromptResult, } from "./session.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ParakeetProvider, useComposer, useStatus, useTimeline, useMarkdown, disclosureOpen, formatToolDuration, formatModelIdentity, formatContextUsage, formatTokenCount, initialToolDisclosure, toggleAllDisclosure, toggleDisclosure, toolCallDefaultOpen, toolGroupDefaultOpen, visibleToolCalls, } from "./headless.js";
|
|
1
|
+
export { ParakeetProvider, useComposer, useStatus, useTimeline, useMarkdown, disclosureOpen, formatToolDuration, formatModelIdentity, formatModelWithLevel, formatContextUsage, formatTokenCount, initialToolDisclosure, toggleAllDisclosure, toggleDisclosure, toolCallDefaultOpen, toolGroupDefaultOpen, visibleToolCalls, } from "./headless.js";
|
|
2
2
|
export { Parakeet, ParakeetView } from "./parakeet.js";
|
|
3
3
|
export { InteractionPanel, } from "./components/InteractionPanel.js";
|
|
4
4
|
export * from "./agent-head.js";
|
package/dist/model-commands.js
CHANGED
|
@@ -4,18 +4,27 @@ import { z } from "zod";
|
|
|
4
4
|
import { loginRegistry, signInProvider, } from "./account-commands.js";
|
|
5
5
|
import { providerChoices } from "./provider-choices.js";
|
|
6
6
|
const defaultChoice = "default";
|
|
7
|
+
// Session-local picker memory survives contribution refreshes, not the owner.
|
|
8
|
+
const recentModels = new WeakMap();
|
|
9
|
+
/** Private memory ceiling, independent of how many models a provider offers. */
|
|
10
|
+
const maximumRememberedProviders = 256;
|
|
7
11
|
function modelLabel(model) {
|
|
8
12
|
return `${model.providerName} · ${model.name}`;
|
|
9
13
|
}
|
|
10
|
-
/**
|
|
11
|
-
function orderModels(models, current) {
|
|
14
|
+
/** Each provider's current or last-used model first, then catalog order. */
|
|
15
|
+
function orderModels(models, current, recent) {
|
|
12
16
|
return [...models].sort((left, right) => {
|
|
13
|
-
const
|
|
14
|
-
|
|
17
|
+
const leftPreference = current?.providerId === left.providerId
|
|
18
|
+
? current
|
|
19
|
+
: recent.get(left.providerId);
|
|
20
|
+
const rightPreference = current?.providerId === right.providerId
|
|
21
|
+
? current
|
|
22
|
+
: recent.get(right.providerId);
|
|
23
|
+
const leftCurrent = left.id === leftPreference?.modelId;
|
|
24
|
+
const rightCurrent = right.id === rightPreference?.modelId;
|
|
15
25
|
if (leftCurrent !== rightCurrent)
|
|
16
26
|
return leftCurrent ? -1 : 1;
|
|
17
|
-
return
|
|
18
|
-
left.name.localeCompare(right.name));
|
|
27
|
+
return left.providerName.localeCompare(right.providerName);
|
|
19
28
|
});
|
|
20
29
|
}
|
|
21
30
|
async function chooseReasoning(interaction, model, current) {
|
|
@@ -82,7 +91,7 @@ async function chooseProviderModels(interaction, models, account, refreshModels)
|
|
|
82
91
|
let catalog = models;
|
|
83
92
|
if (!access.some((candidate) => candidate.providerId === providerId)) {
|
|
84
93
|
await signInProvider(owner, provider, interaction);
|
|
85
|
-
catalog = await refreshModels(interaction.signal);
|
|
94
|
+
catalog = await interaction.run(() => refreshModels(interaction.signal));
|
|
86
95
|
}
|
|
87
96
|
const selectedModels = catalog
|
|
88
97
|
.filter((model) => model.providerId === providerId)
|
|
@@ -93,6 +102,20 @@ async function chooseProviderModels(interaction, models, account, refreshModels)
|
|
|
93
102
|
}
|
|
94
103
|
/** Describe and invoke the ordinary model-preference owner from any client. */
|
|
95
104
|
export function sessionModelCommandDefinitions(session, options) {
|
|
105
|
+
const recent = recentModels.get(session.modelPreference.read) ??
|
|
106
|
+
new Map();
|
|
107
|
+
recentModels.set(session.modelPreference.read, recent);
|
|
108
|
+
const remember = (preference) => {
|
|
109
|
+
if (preference === null)
|
|
110
|
+
return;
|
|
111
|
+
recent.delete(preference.providerId);
|
|
112
|
+
recent.set(preference.providerId, preference);
|
|
113
|
+
if (recent.size > maximumRememberedProviders) {
|
|
114
|
+
const oldest = recent.keys().next().value;
|
|
115
|
+
if (oldest !== undefined)
|
|
116
|
+
recent.delete(oldest);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
96
119
|
const preferenceSchema = z
|
|
97
120
|
.record(z.string(), z.json())
|
|
98
121
|
.parse(modelPreferenceJsonSchema);
|
|
@@ -117,7 +140,7 @@ export function sessionModelCommandDefinitions(session, options) {
|
|
|
117
140
|
agent: {},
|
|
118
141
|
palette: {},
|
|
119
142
|
help: {},
|
|
120
|
-
slash: { aliases: ["model"] },
|
|
143
|
+
slash: { aliases: ["model"], consumesDraft: true },
|
|
121
144
|
},
|
|
122
145
|
action: {
|
|
123
146
|
inputSchema: {
|
|
@@ -132,42 +155,43 @@ export function sessionModelCommandDefinitions(session, options) {
|
|
|
132
155
|
if (input.origin === "agent" || interaction === undefined)
|
|
133
156
|
return session.modelPreference.read();
|
|
134
157
|
const current = await session.modelPreference.read();
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
158
|
+
remember(current);
|
|
159
|
+
const providerModels = await chooseProviderModels(interaction, options.models, options.account, options.refreshModels);
|
|
160
|
+
if (providerModels === null) {
|
|
161
|
+
await interaction.run(() => session.modelPreference.set(null));
|
|
162
|
+
return interaction.run(() => session.modelPreference.read());
|
|
139
163
|
}
|
|
164
|
+
const ordered = orderModels(providerModels, current, recent);
|
|
140
165
|
const answer = await interaction.prompt({
|
|
141
166
|
type: "choice",
|
|
142
167
|
message: "Model",
|
|
143
|
-
options:
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
: modelLabel(model),
|
|
151
|
-
})),
|
|
152
|
-
],
|
|
168
|
+
options: ordered.map((model, index) => ({
|
|
169
|
+
value: String(index),
|
|
170
|
+
label: model.providerId === current?.providerId &&
|
|
171
|
+
model.id === current.modelId
|
|
172
|
+
? `${modelLabel(model)} (current)`
|
|
173
|
+
: modelLabel(model),
|
|
174
|
+
})),
|
|
153
175
|
});
|
|
154
|
-
const model =
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
176
|
+
const model = ordered[Number(answer)];
|
|
177
|
+
if (model === undefined)
|
|
178
|
+
throw new WhistleActionError("model_unavailable", "Choose a listed model.");
|
|
179
|
+
const previous = current?.providerId === model.providerId
|
|
180
|
+
? current
|
|
181
|
+
: recent.get(model.providerId);
|
|
182
|
+
const reasoning = await chooseReasoning(interaction, model, previous?.reasoning);
|
|
183
|
+
const chosen = reasoning === undefined
|
|
184
|
+
? { providerId: model.providerId, modelId: model.id }
|
|
185
|
+
: {
|
|
186
|
+
providerId: model.providerId,
|
|
187
|
+
modelId: model.id,
|
|
188
|
+
reasoning,
|
|
189
|
+
};
|
|
190
|
+
await interaction.run(() => session.modelPreference.set(chosen));
|
|
191
|
+
remember(chosen);
|
|
168
192
|
// The mounted owner's effective-model label confirms the choice.
|
|
169
193
|
// A success notice would keep the choice dialog focused until Esc.
|
|
170
|
-
return session.modelPreference.read();
|
|
194
|
+
return interaction.run(() => session.modelPreference.read());
|
|
171
195
|
}
|
|
172
196
|
let preference;
|
|
173
197
|
try {
|
|
@@ -187,6 +211,7 @@ export function sessionModelCommandDefinitions(session, options) {
|
|
|
187
211
|
throw new WhistleActionError("reasoning_unavailable", "That thinking level is not supported by this model");
|
|
188
212
|
}
|
|
189
213
|
await session.modelPreference.set(preference);
|
|
214
|
+
remember(preference);
|
|
190
215
|
return session.modelPreference.read();
|
|
191
216
|
},
|
|
192
217
|
},
|
|
@@ -216,8 +241,8 @@ export function sessionModelCommandDefinitions(session, options) {
|
|
|
216
241
|
const chosen = reasoning === undefined
|
|
217
242
|
? { providerId: model.providerId, modelId: model.id }
|
|
218
243
|
: { providerId: model.providerId, modelId: model.id, reasoning };
|
|
219
|
-
await session.modelPreference.set(chosen);
|
|
220
|
-
return session.modelPreference.read();
|
|
244
|
+
await interaction.run(() => session.modelPreference.set(chosen));
|
|
245
|
+
return interaction.run(() => session.modelPreference.read());
|
|
221
246
|
},
|
|
222
247
|
},
|
|
223
248
|
];
|
package/dist/parakeet.js
CHANGED
|
@@ -8,6 +8,7 @@ import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
|
|
|
8
8
|
import { ParakeetProvider, useComposer, useClientContributions, useDismissFailedPrompt, useStatus, useTimeline, } from "./conversation.js";
|
|
9
9
|
import { initialToolDisclosure, toggleDisclosure } from "./core/tool-groups.js";
|
|
10
10
|
import { authorDisplayNames, } from "./core/author-labels.js";
|
|
11
|
+
import { useTimelineItemKey } from "./core/use-timeline-item-key.js";
|
|
11
12
|
import { ChatComposer, sessionReadout, } from "./components/ChatComposer.js";
|
|
12
13
|
import { ClientRows } from "./components/ClientRows.js";
|
|
13
14
|
import { useClientActions } from "./client-contributions.js";
|
|
@@ -31,7 +32,11 @@ export function ParakeetView({ disambiguateAuthors, visitor, composerActionVaria
|
|
|
31
32
|
const clientActions = useClientActions(commands ?? ownCommands);
|
|
32
33
|
const contributions = useClientContributions();
|
|
33
34
|
const timelineController = useTimeline();
|
|
34
|
-
const placed = useMemo(() => placeClientTimeline(contributions, timelineController.commandAnchors
|
|
35
|
+
const placed = useMemo(() => placeClientTimeline(contributions, timelineController.commandAnchors, timelineController.positionAnchors), [
|
|
36
|
+
contributions,
|
|
37
|
+
timelineController.commandAnchors,
|
|
38
|
+
timelineController.positionAnchors,
|
|
39
|
+
]);
|
|
35
40
|
return (_jsxs("div", { className: "parakeet flex h-full flex-col items-stretch", "data-parakeet": "standalone", "data-testid": "parakeet-view", onClickCapture: (event) => {
|
|
36
41
|
const anchor = event.target instanceof Element
|
|
37
42
|
? event.target.closest("a[href]")
|
|
@@ -85,19 +90,20 @@ function ConversationInteraction({ slash, }) {
|
|
|
85
90
|
return (_jsx(Dialog, { open: open !== undefined, onOpenChange: (next) => {
|
|
86
91
|
if (!next)
|
|
87
92
|
slash.store.close();
|
|
88
|
-
}, children: _jsx(DialogContent, { className: "w-[min(32rem,calc(100vw-2rem))] rounded-box bg-base-100 p-md shadow-lg", keepMounted: false, children: open === undefined ? null : (_jsx(InteractionPanel, { host: open.host, onClose: slash.store.close,
|
|
89
|
-
slash.store.close();
|
|
90
|
-
open.retry();
|
|
91
|
-
} }, open.key)) }) }));
|
|
93
|
+
}, children: _jsx(DialogContent, { className: "w-[min(32rem,calc(100vw-2rem))] rounded-box bg-base-100 p-md shadow-lg", keepMounted: false, children: open === undefined ? null : (_jsx(InteractionPanel, { host: open.host, onClose: slash.store.close }, open.key)) }) }));
|
|
92
94
|
}
|
|
93
95
|
function ConversationTimeline({ disambiguateAuthors, clientActions, onOpen, focusAfterJump, empty, renderToolActions, renderAssistantAttachment, formatAssistantText, }) {
|
|
94
96
|
const dismissFailed = useDismissFailedPrompt();
|
|
95
97
|
const timelineController = useTimeline();
|
|
98
|
+
const cancelQueued = useCallback((commandId) => {
|
|
99
|
+
void timelineController.cancelQueued(commandId);
|
|
100
|
+
}, [timelineController.cancelQueued]);
|
|
96
101
|
const authorNames = useMemo(() => authorDisplayNames(disambiguateAuthors
|
|
97
102
|
? [...timelineController.settled, ...timelineController.tail].flatMap((item) => ("author" in item && item.author ? [item.author] : []))
|
|
98
103
|
: []), [disambiguateAuthors, timelineController.settled, timelineController.tail]);
|
|
99
104
|
const contributions = useClientContributions();
|
|
100
|
-
const placed = placeClientTimeline(contributions, timelineController.commandAnchors);
|
|
105
|
+
const placed = placeClientTimeline(contributions, timelineController.commandAnchors, timelineController.positionAnchors);
|
|
106
|
+
const before = placed.before.map(({ entryId, cell }) => (_jsx(ClientRows, { entryId: entryId, rows: cell.rows, actions: clientActions, onOpen: onOpen }, `${entryId}:${cell.id}`)));
|
|
101
107
|
// View-only: kept above the virtualizer so off-screen groups remember it.
|
|
102
108
|
const [toolDisclosure, setToolDisclosure] = useState(initialToolDisclosure);
|
|
103
109
|
const toggleTool = useCallback((id, defaultOpen) => {
|
|
@@ -110,15 +116,7 @@ function ConversationTimeline({ disambiguateAuthors, clientActions, onOpen, focu
|
|
|
110
116
|
const itemAt = useCallback((index) => index < timelineController.settled.length
|
|
111
117
|
? timelineController.settled[index]
|
|
112
118
|
: timelineController.tail[index - timelineController.settled.length], [timelineController.settled, timelineController.tail]);
|
|
113
|
-
const getItemKey =
|
|
114
|
-
const item = itemAt(index);
|
|
115
|
-
if (item === undefined)
|
|
116
|
-
return index;
|
|
117
|
-
// One submitted prompt keeps one row from submit to durable: no remount.
|
|
118
|
-
return item.kind === "user_message" && item.requestId !== undefined
|
|
119
|
-
? item.requestId
|
|
120
|
-
: item.id;
|
|
121
|
-
}, [itemAt]);
|
|
119
|
+
const getItemKey = useTimelineItemKey(timelineController.settled, timelineController.tail);
|
|
122
120
|
const timeline = useVirtualizer({
|
|
123
121
|
anchorTo: "end",
|
|
124
122
|
count,
|
|
@@ -200,7 +198,7 @@ function ConversationTimeline({ disambiguateAuthors, clientActions, onOpen, focu
|
|
|
200
198
|
top: 0,
|
|
201
199
|
transform: `translateY(${String(virtualItem.start)}px)`,
|
|
202
200
|
width: "100%",
|
|
203
|
-
}, children: [_jsx(TimelineItem, { item: "author" in item &&
|
|
201
|
+
}, children: [virtualItem.index === 0 ? before : null, _jsx(TimelineItem, { item: "author" in item &&
|
|
204
202
|
item.author &&
|
|
205
203
|
authorNames.has(item.author.id)
|
|
206
204
|
? {
|
|
@@ -211,8 +209,8 @@ function ConversationTimeline({ disambiguateAuthors, clientActions, onOpen, focu
|
|
|
211
209
|
item.author.name,
|
|
212
210
|
},
|
|
213
211
|
}
|
|
214
|
-
: item, onDismissFailed: dismissFailed, onToggleTool: toggleTool, renderToolActions: renderToolActions, renderAssistantAttachment: renderAssistantAttachment, formatAssistantText: formatAssistantText, toolDisclosure: toolDisclosure }), placed.after.get(item.id)?.map(({ entryId, cell }) => (_jsx(ClientRows, { entryId: entryId, rows: cell.rows, actions: clientActions, onOpen: onOpen }, `${entryId}:${cell.id}`)))] }, virtualItem.key));
|
|
215
|
-
}) })) : ((empty ?? (_jsx("div", { className: "flex h-full items-center justify-center text-center", children: _jsxs("div", { children: [_jsx("p", { className: "mb-1 text-xs text-base-content", children: "Ready" }), _jsx("p", { className: "text-[10px] text-dim", children: "What would you like to build?" })] }) })))) }), count > 0 ? (_jsx(ScrollToBottomBlob, { direction: "forward", unread: unread, focusAfterJump: focusAfterJump, onJump: jumpToBottom, scrollerRef: scrollerRef })) : null] }));
|
|
212
|
+
: item, onDismissFailed: dismissFailed, onCancelQueued: cancelQueued, cancellingQueued: timelineController.cancellingQueued, onToggleTool: toggleTool, renderToolActions: renderToolActions, renderAssistantAttachment: renderAssistantAttachment, formatAssistantText: formatAssistantText, toolDisclosure: toolDisclosure }), placed.after.get(item.id)?.map(({ entryId, cell }) => (_jsx(ClientRows, { entryId: entryId, rows: cell.rows, actions: clientActions, onOpen: onOpen }, `${entryId}:${cell.id}`)))] }, virtualItem.key));
|
|
213
|
+
}) })) : before.length > 0 ? (before) : hasMoreHistory ? null : ((empty ?? (_jsx("div", { className: "flex h-full items-center justify-center text-center", children: _jsxs("div", { children: [_jsx("p", { className: "mb-1 text-xs text-base-content", children: "Ready" }), _jsx("p", { className: "text-[10px] text-dim", children: "What would you like to build?" })] }) })))) }), count > 0 ? (_jsx(ScrollToBottomBlob, { direction: "forward", unread: unread, focusAfterJump: focusAfterJump, onJump: jumpToBottom, scrollerRef: scrollerRef })) : null] }));
|
|
216
214
|
}
|
|
217
215
|
/** The owner's queued state and independently contributed waiting controls. */
|
|
218
216
|
function ConversationWaiting({ clientActions, }) {
|
|
@@ -243,6 +241,7 @@ function ConversationComposer({ visitor, textareaRef, composerActionVariant, sla
|
|
|
243
241
|
void composer.cancel();
|
|
244
242
|
}, [composer.cancel]);
|
|
245
243
|
const composerProps = {
|
|
244
|
+
queuedRecall: visitor === undefined ? composer : undefined,
|
|
246
245
|
statusChips: contributions
|
|
247
246
|
.flatMap(({ value }) => value.chips)
|
|
248
247
|
.sort((left, right) => left.order - right.order)
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { CancelResult } from "@fungi.computer/shiitake/client";
|
|
2
1
|
import type { ParakeetSessionCommand } from "./session.js";
|
|
3
2
|
import type { WhistleRuntime } from "@fungi.computer/whistle";
|
|
4
3
|
import { buildDurableTimeline } from "./core/build-timeline.js";
|
|
@@ -18,10 +17,6 @@ export type SessionCommandSession = Readonly<{
|
|
|
18
17
|
}>[];
|
|
19
18
|
}>;
|
|
20
19
|
}> & SessionViewFacts>;
|
|
21
|
-
cancel?: ((input: Readonly<{
|
|
22
|
-
commandId: string;
|
|
23
|
-
onlyIfPending?: boolean;
|
|
24
|
-
}>) => Promise<CancelResult>) | undefined;
|
|
25
20
|
/** Execute a type-discriminated Session command, including `fork`. */
|
|
26
21
|
command: ParakeetSessionCommand;
|
|
27
22
|
}>;
|
|
@@ -35,10 +30,6 @@ export type ParakeetSessionCommandOptions = Readonly<{
|
|
|
35
30
|
sessionResume?: (() => void | Promise<void>) | undefined;
|
|
36
31
|
/** Whether this host currently supports saved-Session selection. */
|
|
37
32
|
sessionResumeAvailable: boolean;
|
|
38
|
-
/** Restore an owner-withdrawn queued prompt into the host composer. */
|
|
39
|
-
onEditQueued?: (text: string) => void;
|
|
40
|
-
/** Refuse withdrawal while the host has a draft that must be preserved. */
|
|
41
|
-
canEditQueued?: () => boolean;
|
|
42
33
|
/** Navigate to the Session a fork just created. */
|
|
43
34
|
onForked?: ((sessionId: string) => void | Promise<void>) | undefined;
|
|
44
35
|
/** Whether this host currently supports navigating to a forked Session. */
|