@jini-ai/chat 0.6.6 → 0.6.10
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/CHANGELOG.md +129 -1
- package/dist/core/accepted-input.d.ts +54 -0
- package/dist/core/accepted-input.js +165 -0
- package/dist/core/agent-plugin-chat-state.d.ts +43 -0
- package/dist/core/agent-plugin-chat-state.js +48 -0
- package/dist/core/assistant-client/a2ui-action-poster.js +32 -28
- package/dist/core/assistant-client/messages.d.ts +1 -1
- package/dist/core/assistant-client/messages.js +2 -2
- package/dist/core/assistant-client/transport.d.ts +2 -2
- package/dist/core/assistant-client/transport.js +187 -98
- package/dist/core/assistant-content.d.ts +2 -1
- package/dist/core/assistant-content.js +9 -11
- package/dist/core/browser/page-actions.js +4 -2
- package/dist/core/composer-history.d.ts +16 -9
- package/dist/core/composer-history.js +28 -16
- package/dist/core/conversation-title.d.ts +3 -0
- package/dist/core/conversation-title.js +3 -0
- package/dist/core/durable-projection.js +20 -13
- package/dist/core/durable-runs/continuation.d.ts +4 -0
- package/dist/core/durable-runs/continuation.js +31 -6
- package/dist/core/durable-runs/ledger-contracts.d.ts +2 -1
- package/dist/core/durable-runs/ports.d.ts +6 -2
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +2 -0
- package/dist/core/messages.d.ts +2 -0
- package/dist/core/partial-json.d.ts +6 -7
- package/dist/core/partial-json.js +81 -47
- package/dist/core/persistence/title.js +4 -2
- package/dist/core/question-answer.d.ts +23 -0
- package/dist/core/question-answer.js +66 -0
- package/dist/core/question-form/format.d.ts +6 -6
- package/dist/core/question-form/format.js +16 -17
- package/dist/core/question-form/normalize.d.ts +18 -0
- package/dist/core/question-form/normalize.js +112 -122
- package/dist/core/question-form/scan.js +141 -203
- package/dist/core/run-activity.js +62 -49
- package/dist/core/run-events/entry.d.ts +10 -1
- package/dist/core/run-events/entry.js +117 -87
- package/dist/core/todos.d.ts +1 -1
- package/dist/core/todos.js +60 -85
- package/dist/core/tool-events.js +14 -12
- package/dist/core/transcript.js +62 -16
- package/dist/core/turn-usage.js +54 -32
- package/dist/core/user-text-redaction.js +3 -0
- package/dist/core/util/manifest.js +77 -82
- package/dist/core/util/markdown-context.js +51 -53
- package/dist/core/util/parser.js +136 -144
- package/dist/core/util/pointer.js +16 -16
- package/dist/core/util/strip.js +57 -67
- package/dist/core/util/validate.js +15 -17
- package/dist/embed-widget/browser/session-store.js +21 -12
- package/dist/embed-widget/transports/fetch-sse.js +108 -95
- package/dist/embed-widget/vanilla/index.js +81 -70
- package/dist/react/agent-bridge/frontend-session-bridge.js +80 -52
- package/dist/react/components/AttachmentPreviewModal.js +25 -1
- package/dist/react/components/ChatSettingsDialog.d.ts +13 -0
- package/dist/react/components/ChatSettingsDialog.hooks.d.ts +115 -0
- package/dist/react/components/ChatSettingsDialog.hooks.js +40 -0
- package/dist/react/components/ChatSettingsDialog.js +72 -0
- package/dist/react/components/ChatSettingsSegmented.d.ts +18 -0
- package/dist/react/components/ChatSettingsSegmented.js +11 -0
- package/dist/react/components/Composer.d.ts +5 -1
- package/dist/react/components/Composer.js +126 -82
- package/dist/react/components/ConversationList.js +25 -39
- package/dist/react/components/ConversationTitleEditor.d.ts +27 -0
- package/dist/react/components/ConversationTitleEditor.js +54 -0
- package/dist/react/components/Icon.d.ts +1 -1
- package/dist/react/components/Icon.js +25 -45
- package/dist/react/components/Markdown.js +134 -123
- package/dist/react/components/McpUiSurfaceCard.d.ts +2 -2
- package/dist/react/components/McpUiSurfaceCard.js +30 -9
- package/dist/react/components/MessageList.d.ts +13 -13
- package/dist/react/components/MessageList.hooks.d.ts +6 -1
- package/dist/react/components/MessageList.hooks.js +19 -3
- package/dist/react/components/MessageList.js +34 -10
- package/dist/react/components/MessageRow.d.ts +1 -1
- package/dist/react/components/MessageRow.js +75 -47
- package/dist/react/components/MessageRow.usage.js +16 -11
- package/dist/react/components/MidRunUserMessage.js +16 -3
- package/dist/react/components/QuestionForm.js +148 -76
- package/dist/react/components/QuestionsPanel.js +1 -1
- package/dist/react/components/TodoCard.js +12 -6
- package/dist/react/components/ToolCallGroup.d.ts +4 -3
- package/dist/react/components/ToolCallGroup.js +7 -5
- package/dist/react/components/ToolCard.js +47 -40
- package/dist/react/components/composer-discovery.js +6 -1
- package/dist/react/components/mcp-ui-surface-state.d.ts +6 -11
- package/dist/react/components/mcp-ui-surface-state.js +23 -8
- package/dist/react/ext-event-renderer-registry.d.ts +8 -0
- package/dist/react/ext-event-renderer-registry.js +5 -2
- package/dist/react/features/chat-pane/components/AgentPluginUsage.d.ts +7 -0
- package/dist/react/features/chat-pane/components/AgentPluginUsage.js +45 -0
- package/dist/react/features/chat-pane/components/AgentRuntimePicker.js +55 -19
- package/dist/react/features/chat-pane/components/ChatPane.d.ts +1 -1
- package/dist/react/features/chat-pane/components/ChatPane.js +192 -74
- package/dist/react/features/chat-pane/components/RuntimeDropUp.d.ts +29 -0
- package/dist/react/features/chat-pane/components/RuntimeDropUp.js +45 -0
- package/dist/react/features/chat-pane/create-daemon-attachment-uploader.js +80 -47
- package/dist/react/features/chat-pane/create-mcp-ui-tool-caller.js +44 -40
- package/dist/react/features/chat-pane/create-mid-run-message-poster.d.ts +6 -6
- package/dist/react/features/chat-pane/create-mid-run-message-poster.js +8 -8
- package/dist/react/features/chat-pane/create-typed-answer-poster.d.ts +3 -3
- package/dist/react/features/chat-pane/create-typed-answer-poster.js +3 -3
- package/dist/react/features/chat-pane/hooks/useAgentRuntimePicker.hooks.d.ts +6 -1
- package/dist/react/features/chat-pane/hooks/useAgentRuntimePicker.hooks.js +11 -5
- package/dist/react/features/chat-pane/hooks/useChatPane.hooks.d.ts +12 -7
- package/dist/react/features/chat-pane/hooks/useChatPane.hooks.js +340 -149
- package/dist/react/features/chat-pane/hooks/useChatPaneControlsHeight.hooks.js +7 -6
- package/dist/react/features/chat-pane/hooks/useChatPaneNewTabLinks.hooks.js +28 -10
- package/dist/react/features/chat-pane/hooks/useChatPaneRuntimeInventory.hooks.d.ts +3 -3
- package/dist/react/features/chat-pane/hooks/useChatPaneRuntimeInventory.hooks.js +60 -12
- package/dist/react/features/chat-pane/hooks/useRuntimeDropUp.hooks.d.ts +49 -0
- package/dist/react/features/chat-pane/hooks/useRuntimeDropUp.hooks.js +143 -0
- package/dist/react/features/chat-pane/model-options.d.ts +14 -0
- package/dist/react/features/chat-pane/model-options.js +45 -25
- package/dist/react/features/chat-pane/rules.d.ts +8 -9
- package/dist/react/features/chat-pane/rules.js +84 -46
- package/dist/react/features/chat-pane/styles.d.ts +1 -1
- package/dist/react/features/chat-pane/styles.js +152 -36
- package/dist/react/features/chat-pane/types.d.ts +19 -9
- package/dist/react/hooks/assistant-chats.js +12 -5
- package/dist/react/hooks/composer-draft-cache.js +116 -118
- package/dist/react/hooks/composer-history-storage.js +5 -5
- package/dist/react/hooks/fab-position.js +7 -4
- package/dist/react/hooks/useAnsweredCards.d.ts +21 -4
- package/dist/react/hooks/useAnsweredCards.js +38 -11
- package/dist/react/hooks/useArtifactStream.js +28 -22
- package/dist/react/hooks/useComposer.d.ts +20 -0
- package/dist/react/hooks/useComposer.js +22 -9
- package/dist/react/hooks/useComposerHistory.hooks.d.ts +6 -1
- package/dist/react/hooks/useComposerHistory.hooks.js +39 -19
- package/dist/react/hooks/useComposerHistoryKeys.hooks.js +24 -14
- package/dist/react/hooks/useConversation.d.ts +7 -0
- package/dist/react/hooks/useConversation.js +23 -10
- package/dist/react/hooks/useExtEventGroups.js +39 -39
- package/dist/react/hooks/useQuestionForms.js +21 -26
- package/dist/react/hooks/useRunStream.js +10 -2
- package/dist/react/index.d.ts +7 -1
- package/dist/react/index.js +9 -0
- package/dist/react/message-blocks.d.ts +6 -4
- package/dist/react/message-blocks.js +94 -72
- package/dist/react/slots.d.ts +2 -2
- package/dist/react/tool-call-display.d.ts +12 -6
- package/dist/react/tool-call-display.js +53 -24
- package/dist/server/durable-runs/recover.js +132 -80
- package/dist/server/run-finalizer/entry.js +25 -15
- package/dist/store/legacy/sqlite/conversations.d.ts +11 -11
- package/dist/store/legacy/sqlite/conversations.js +69 -98
- package/dist/store/legacy/sqlite/messages.d.ts +10 -2
- package/dist/store/legacy/sqlite/messages.js +113 -71
- package/dist/store/runtime/chat-history-store.js +9 -3
- package/dist/store/runtime/durable-run-store.d.ts +2 -2
- package/dist/store/runtime/durable-run-store.js +165 -117
- package/dist/store/runtime/history-tools.js +118 -82
- package/dist/store/runtime/run-ledger.d.ts +4 -1
- package/dist/store/runtime/run-ledger.js +56 -16
- package/dist/store/sql/cursor.js +38 -18
- package/dist/store/sql/store.d.ts +18 -0
- package/dist/store/sql/store.js +46 -15
- package/package.json +18 -16
|
@@ -25,6 +25,47 @@ function errorFrom(body, status) {
|
|
|
25
25
|
}
|
|
26
26
|
return error;
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* The deadline's abort becomes a readable timeout; every other failure (a network error, a non-2xx
|
|
30
|
+
* rejection) passes through unchanged.
|
|
31
|
+
*/
|
|
32
|
+
function timeoutAware(error, timeoutMs) {
|
|
33
|
+
return error instanceof Error && error.name === 'AbortError'
|
|
34
|
+
? new Error(`Timed out after ${timeoutMs}ms waiting for the server.`)
|
|
35
|
+
: error;
|
|
36
|
+
}
|
|
37
|
+
/** One POST of a confirmed action and its parsed answer; a non-2xx response rejects via {@link errorFrom}. */
|
|
38
|
+
async function postToolCall({ call, endpoint, headers, signal, fetch }) {
|
|
39
|
+
// `{name, arguments}` on the MCP-UI side becomes `{toolName, params}` on the wire: `arguments`
|
|
40
|
+
// is a reserved word in a JS function scope and reads badly in a server handler, and the
|
|
41
|
+
// renamed pair matches what the reference implementation's redemption route already accepts.
|
|
42
|
+
const request = {
|
|
43
|
+
toolName: call.name,
|
|
44
|
+
params: { ...call.arguments },
|
|
45
|
+
};
|
|
46
|
+
const response = await fetch(endpoint, {
|
|
47
|
+
method: 'POST',
|
|
48
|
+
// Same-origin cookie session is the usual authenticator for the human's second step.
|
|
49
|
+
credentials: 'same-origin',
|
|
50
|
+
headers: { ...headers, 'content-type': 'application/json' },
|
|
51
|
+
body: JSON.stringify(request),
|
|
52
|
+
signal,
|
|
53
|
+
});
|
|
54
|
+
const raw = await response.text();
|
|
55
|
+
let parsed = raw;
|
|
56
|
+
if (raw.length > 0) {
|
|
57
|
+
try {
|
|
58
|
+
parsed = JSON.parse(raw);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Left as text — a proxy's HTML error page is more useful surfaced verbatim than swapped
|
|
62
|
+
// for a generic "invalid JSON", which would hide what actually answered.
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (!response.ok)
|
|
66
|
+
throw errorFrom(parsed, response.status);
|
|
67
|
+
return parsed;
|
|
68
|
+
}
|
|
28
69
|
/**
|
|
29
70
|
* Builds an {@link McpUiToolCallHandler} that POSTs `{toolName, params}` and returns the parsed
|
|
30
71
|
* response.
|
|
@@ -45,46 +86,9 @@ export function createMcpUiToolCaller({ baseUrl, fetch }, options = {}) {
|
|
|
45
86
|
return async (call) => {
|
|
46
87
|
const controller = new AbortController();
|
|
47
88
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// renamed pair matches what the reference implementation's redemption route already accepts.
|
|
52
|
-
const request = {
|
|
53
|
-
toolName: call.name,
|
|
54
|
-
params: { ...call.arguments },
|
|
55
|
-
};
|
|
56
|
-
const response = await fetch(endpoint, {
|
|
57
|
-
method: 'POST',
|
|
58
|
-
// Same-origin cookie session is the usual authenticator for the human's second step.
|
|
59
|
-
credentials: 'same-origin',
|
|
60
|
-
headers: { ...options.headers, 'content-type': 'application/json' },
|
|
61
|
-
body: JSON.stringify(request),
|
|
62
|
-
signal: controller.signal,
|
|
63
|
-
});
|
|
64
|
-
const raw = await response.text();
|
|
65
|
-
let parsed = raw;
|
|
66
|
-
if (raw.length > 0) {
|
|
67
|
-
try {
|
|
68
|
-
parsed = JSON.parse(raw);
|
|
69
|
-
}
|
|
70
|
-
catch {
|
|
71
|
-
// Left as text — a proxy's HTML error page is more useful surfaced verbatim than swapped
|
|
72
|
-
// for a generic "invalid JSON", which would hide what actually answered.
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
if (!response.ok)
|
|
76
|
-
throw errorFrom(parsed, response.status);
|
|
77
|
-
return parsed;
|
|
78
|
-
}
|
|
79
|
-
catch (error) {
|
|
80
|
-
if (error instanceof Error && error.name === 'AbortError') {
|
|
81
|
-
throw new Error(`Timed out after ${timeoutMs}ms waiting for the server.`);
|
|
82
|
-
}
|
|
83
|
-
throw error;
|
|
84
|
-
}
|
|
85
|
-
finally {
|
|
86
|
-
clearTimeout(timer);
|
|
87
|
-
}
|
|
89
|
+
return postToolCall({ call, endpoint, headers: options.headers, signal: controller.signal, fetch })
|
|
90
|
+
.catch((error) => { throw timeoutAware(error, timeoutMs); })
|
|
91
|
+
.finally(() => clearTimeout(timer));
|
|
88
92
|
};
|
|
89
93
|
}
|
|
90
94
|
//# sourceMappingURL=create-mcp-ui-tool-caller.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module create-mid-run-message-poster
|
|
3
3
|
*
|
|
4
|
-
* The client half of a mid-run message: a ready-made {@link DeliverMidRunMessage} that posts
|
|
5
|
-
* human
|
|
4
|
+
* The client half of a mid-run message: a ready-made {@link DeliverMidRunMessage} that posts the
|
|
5
|
+
* human's text and attachment refs to the live agent. Pass it as `ChatPane`'s
|
|
6
6
|
* `deliverMidRunMessage`.
|
|
7
7
|
*
|
|
8
8
|
* ```tsx
|
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
* ```
|
|
11
11
|
*
|
|
12
12
|
* Sibling of `create-typed-answer-poster.ts`. The route is `@jini-ai/daemon`'s
|
|
13
|
-
* `POST /api/runs/:runId/messages`: `202` when the agent took the
|
|
13
|
+
* `POST /api/runs/:runId/messages`: `202` when the agent took the whole turn, `409`
|
|
14
14
|
* with `details.delivery` when it did not.
|
|
15
15
|
*
|
|
16
16
|
* ## Why it resolves an outcome instead of throwing
|
|
17
17
|
*
|
|
18
18
|
* The pane acts differently on each outcome and must never drop the text: `'unsupported'` stops the
|
|
19
|
-
* run
|
|
20
|
-
*
|
|
19
|
+
* run for text-only turns, or queues an attachment turn intact; `'not-running'` queues behind the
|
|
20
|
+
* ending run; `'failed'` retains the draft for retry. A 404 means
|
|
21
21
|
* the daemon never saw this run (a host-side run such as a BYOK API turn), so it is `'unsupported'`
|
|
22
22
|
* too: no live process to steer, but an interrupt still works.
|
|
23
23
|
*/
|
|
@@ -30,7 +30,7 @@ export interface CreateMidRunMessagePosterOptions extends UserTextRedactionOptio
|
|
|
30
30
|
readonly headers?: Readonly<Record<string, string>>;
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Posts text and optional opaque attachment refs to `${baseUrl}/api/runs/:runId/messages`.
|
|
34
34
|
*
|
|
35
35
|
* @param deps.baseUrl - Origin to call; `''` for same-origin.
|
|
36
36
|
* @param deps.fetch - The fetch to use (the browser's, in production).
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module create-mid-run-message-poster
|
|
3
3
|
*
|
|
4
|
-
* The client half of a mid-run message: a ready-made {@link DeliverMidRunMessage} that posts
|
|
5
|
-
* human
|
|
4
|
+
* The client half of a mid-run message: a ready-made {@link DeliverMidRunMessage} that posts the
|
|
5
|
+
* human's text and attachment refs to the live agent. Pass it as `ChatPane`'s
|
|
6
6
|
* `deliverMidRunMessage`.
|
|
7
7
|
*
|
|
8
8
|
* ```tsx
|
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
* ```
|
|
11
11
|
*
|
|
12
12
|
* Sibling of `create-typed-answer-poster.ts`. The route is `@jini-ai/daemon`'s
|
|
13
|
-
* `POST /api/runs/:runId/messages`: `202` when the agent took the
|
|
13
|
+
* `POST /api/runs/:runId/messages`: `202` when the agent took the whole turn, `409`
|
|
14
14
|
* with `details.delivery` when it did not.
|
|
15
15
|
*
|
|
16
16
|
* ## Why it resolves an outcome instead of throwing
|
|
17
17
|
*
|
|
18
18
|
* The pane acts differently on each outcome and must never drop the text: `'unsupported'` stops the
|
|
19
|
-
* run
|
|
20
|
-
*
|
|
19
|
+
* run for text-only turns, or queues an attachment turn intact; `'not-running'` queues behind the
|
|
20
|
+
* ending run; `'failed'` retains the draft for retry. A 404 means
|
|
21
21
|
* the daemon never saw this run (a host-side run such as a BYOK API turn), so it is `'unsupported'`
|
|
22
22
|
* too: no live process to steer, but an interrupt still works.
|
|
23
23
|
*/
|
|
@@ -38,7 +38,7 @@ async function deliveryFor(response) {
|
|
|
38
38
|
return response.status === 404 ? 'unsupported' : 'failed';
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
|
-
*
|
|
41
|
+
* Posts text and optional opaque attachment refs to `${baseUrl}/api/runs/:runId/messages`.
|
|
42
42
|
*
|
|
43
43
|
* @param deps.baseUrl - Origin to call; `''` for same-origin.
|
|
44
44
|
* @param deps.fetch - The fetch to use (the browser's, in production).
|
|
@@ -48,7 +48,7 @@ async function deliveryFor(response) {
|
|
|
48
48
|
export function createMidRunMessagePoster({ baseUrl, fetch }, options = {}) {
|
|
49
49
|
const origin = baseUrl.replace(/\/$/u, '');
|
|
50
50
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
51
|
-
return async ({ runId, text }) => {
|
|
51
|
+
return async ({ runId, text, attachments }) => {
|
|
52
52
|
const result = (options.redactUserText ?? redactUserText)({ text });
|
|
53
53
|
if (result.secretRedacted)
|
|
54
54
|
options.onSecretRedacted?.({ secretRedacted: true, count: result.count });
|
|
@@ -59,7 +59,7 @@ export function createMidRunMessagePoster({ baseUrl, fetch }, options = {}) {
|
|
|
59
59
|
// Same-origin cookie session: the human's own credentials authorize steering their run.
|
|
60
60
|
credentials: 'same-origin',
|
|
61
61
|
headers: { ...options.headers, 'content-type': 'application/json' },
|
|
62
|
-
body: JSON.stringify({ text: result.text }),
|
|
62
|
+
body: JSON.stringify({ text: result.text, ...(attachments?.length ? { attachmentIds: attachments.map(attachment => attachment.path) } : {}) }),
|
|
63
63
|
signal: controller.signal,
|
|
64
64
|
}).then(deliveryFor, () => 'failed');
|
|
65
65
|
clearTimeout(timer);
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
*
|
|
23
23
|
* ## Why it resolves an outcome instead of throwing
|
|
24
24
|
*
|
|
25
|
-
* The pane
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* The pane tells three cases apart: 202 delivered the answer; 409 means nothing is waiting and
|
|
26
|
+
* permits one ordinary-message fallback; other failures retain the draft for retry. A rejection
|
|
27
|
+
* would collapse the last two and risk resending an answer whose delivery was uncertain.
|
|
28
28
|
*/
|
|
29
29
|
import { type UserTextRedactionOptions } from '../../../core/user-text-redaction.js';
|
|
30
30
|
import type { DeliverTypedAnswer } from './types.js';
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
*
|
|
23
23
|
* ## Why it resolves an outcome instead of throwing
|
|
24
24
|
*
|
|
25
|
-
* The pane
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* The pane tells three cases apart: 202 delivered the answer; 409 means nothing is waiting and
|
|
26
|
+
* permits one ordinary-message fallback; other failures retain the draft for retry. A rejection
|
|
27
|
+
* would collapse the last two and risk resending an answer whose delivery was uncertain.
|
|
28
28
|
*/
|
|
29
29
|
import { redactUserText } from '../../../core/user-text-redaction.js';
|
|
30
30
|
/**
|
|
@@ -38,7 +38,10 @@ export declare function runtimeOptionLabel({ options, value, fallback }: {
|
|
|
38
38
|
fallback: string;
|
|
39
39
|
}): string;
|
|
40
40
|
/**
|
|
41
|
-
* Computes a viewport-bounded fixed position for the body-portaled picker
|
|
41
|
+
* Computes a viewport-bounded fixed position for the body-portaled picker, centred on the trigger
|
|
42
|
+
* and clamped into the viewport and (when given) into `bounds`. `bounds` (the composer box) keeps a
|
|
43
|
+
* popover centred on an icon near a narrow dock's left edge from spilling onto the page beside it,
|
|
44
|
+
* the same clamp `runtimeDropUpPosition` applies to the model/effort drop-ups.
|
|
42
45
|
*
|
|
43
46
|
* @complexity Time/space: O(1).
|
|
44
47
|
* @overallScore 100/100
|
|
@@ -46,6 +49,8 @@ export declare function runtimeOptionLabel({ options, value, fallback }: {
|
|
|
46
49
|
export declare function runtimePopoverPosition({ trigger, placement }: {
|
|
47
50
|
trigger: DOMRect;
|
|
48
51
|
placement: RuntimePickerPlacement;
|
|
52
|
+
}, { bounds }?: {
|
|
53
|
+
bounds?: Pick<DOMRect, 'left' | 'right'>;
|
|
49
54
|
}): CSSProperties;
|
|
50
55
|
/** `Tab` wraps focus around the popover's control list instead of leaving it (the popover is a
|
|
51
56
|
* modal-ish dialog). Returns the index to wrap TO, or `null` when `Tab` should behave natively
|
|
@@ -38,16 +38,21 @@ export function runtimeOptionLabel({ options, value, fallback }) {
|
|
|
38
38
|
return options?.find((option) => option.id === value)?.label ?? value;
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
|
-
* Computes a viewport-bounded fixed position for the body-portaled picker
|
|
41
|
+
* Computes a viewport-bounded fixed position for the body-portaled picker, centred on the trigger
|
|
42
|
+
* and clamped into the viewport and (when given) into `bounds`. `bounds` (the composer box) keeps a
|
|
43
|
+
* popover centred on an icon near a narrow dock's left edge from spilling onto the page beside it,
|
|
44
|
+
* the same clamp `runtimeDropUpPosition` applies to the model/effort drop-ups.
|
|
42
45
|
*
|
|
43
46
|
* @complexity Time/space: O(1).
|
|
44
47
|
* @overallScore 100/100
|
|
45
48
|
*/
|
|
46
|
-
export function runtimePopoverPosition({ trigger, placement }) {
|
|
49
|
+
export function runtimePopoverPosition({ trigger, placement }, { bounds } = {}) {
|
|
47
50
|
const margin = 12;
|
|
48
51
|
const gap = 8;
|
|
49
|
-
const
|
|
50
|
-
const
|
|
52
|
+
const minLeft = Math.max(margin, bounds?.left ?? -Infinity);
|
|
53
|
+
const maxRight = Math.min(window.innerWidth - margin, bounds?.right ?? Infinity);
|
|
54
|
+
const width = Math.max(0, Math.min(320, maxRight - minLeft));
|
|
55
|
+
const left = Math.min(Math.max(trigger.left + trigger.width / 2 - width / 2, minLeft), maxRight - width);
|
|
51
56
|
if (placement === 'up') {
|
|
52
57
|
const availableHeight = Math.max(0, trigger.top - margin - gap);
|
|
53
58
|
return {
|
|
@@ -205,8 +210,9 @@ export function useAgentRuntimePicker({ agents, value, placement, t, executionMo
|
|
|
205
210
|
return;
|
|
206
211
|
const update = () => {
|
|
207
212
|
const rect = triggerRef.current?.getBoundingClientRect();
|
|
213
|
+
const bounds = triggerRef.current?.closest('.jini-composer')?.getBoundingClientRect();
|
|
208
214
|
if (rect)
|
|
209
|
-
setPosition(runtimePopoverPosition({ trigger: rect, placement: placement }));
|
|
215
|
+
setPosition(runtimePopoverPosition({ trigger: rect, placement: placement }, bounds ? { bounds } : {}));
|
|
210
216
|
};
|
|
211
217
|
update();
|
|
212
218
|
window.addEventListener('resize', update);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type AcceptedChatInput } from '../../../../core/accepted-input.js';
|
|
1
2
|
import type { UserTextRedactionOptions } from '../../../../core/user-text-redaction.js';
|
|
2
3
|
import { type ChatPaneSendBlocker } from '../rules.js';
|
|
3
4
|
import type { ChatPaneActivity, ChatPaneAgent, ChatPaneAttachmentUploadOptions, ChatPaneAgentSelection, ChatPaneRunContext, ChatPaneWorkingDirectoryAccess, DeliverMidRunMessage, DeliverTypedAnswer, TypedAnswerNotice } from '../types.js';
|
|
@@ -20,6 +21,8 @@ export interface UseChatPaneOptions extends UserTextRedactionOptions {
|
|
|
20
21
|
initialDraft?: string;
|
|
21
22
|
composerHistoryScope?: string;
|
|
22
23
|
composerHistoryStorage?: ComposerHistoryStoragePort;
|
|
24
|
+
/** Recall retention; defaults to 100. */
|
|
25
|
+
composerHistoryCap?: number;
|
|
23
26
|
/** Forwarded verbatim to `useComposer`; see `validateAttachments` there for the contract. */
|
|
24
27
|
validateAttachments?: (attachments: readonly ChatAttachment[]) => Promise<readonly ChatAttachment[]>;
|
|
25
28
|
uploadAttachments?: (files: File[], options?: ChatPaneAttachmentUploadOptions) => Promise<ChatAttachment[]>;
|
|
@@ -85,20 +88,22 @@ export interface UseChatPaneResult extends UseChatPaneWorkingDirectoryResult {
|
|
|
85
88
|
* was silently swallowed.
|
|
86
89
|
*/
|
|
87
90
|
queuedPrompt: string | null;
|
|
91
|
+
/** Individual queued messages, in send order, with their own staged files. */
|
|
92
|
+
queuedMessages: readonly AcceptedChatInput[];
|
|
93
|
+
/** Drops only the named queued message. */
|
|
94
|
+
cancelQueuedMessage: (input: {
|
|
95
|
+
id: string;
|
|
96
|
+
}, options?: {}) => void;
|
|
88
97
|
/** Drops the queued prompt without ever sending it. */
|
|
89
98
|
cancelQueued: () => void;
|
|
90
99
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* whose question has since closed; the draft stays in the composer. Cleared by the next send and
|
|
94
|
-
* by `reset()`.
|
|
100
|
+
* Delivery failure for the last typed answer, or `null`. Failures retain the draft; a definitive
|
|
101
|
+
* not-pending refusal queues one ordinary message instead. Cleared by the next send and `reset()`.
|
|
95
102
|
*/
|
|
96
103
|
typedAnswerNotice: TypedAnswerNotice | null;
|
|
97
104
|
/**
|
|
98
105
|
* Sends the composer draft as an ordinary next turn (queued behind a running run, as {@link send}
|
|
99
|
-
* does)
|
|
100
|
-
* past {@link send}'s hold on such a draft other than clearing it: the human chose a new, possibly
|
|
101
|
-
* paid, run on purpose.
|
|
106
|
+
* does), bypassing typed-answer routing.
|
|
102
107
|
*/
|
|
103
108
|
sendAsNewMessage: () => Promise<void>;
|
|
104
109
|
/**
|