@7n/tauri-components 0.13.5 → 0.13.7
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 +12 -0
- package/package.json +1 -1
- package/src/components/AgentDialog.vue +36 -5
- package/src/components/docs/AgentDialog.md +1 -1
- package/src/core/acp-kit.js +29 -12
- package/src/core/docs/acp-kit.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.13.7] - 2026-07-20
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- acp_spawn_agent тепер чекає на реальний успіх/провал initialize+session/new перед поверненням session key (усуває гонку з acp_prompt, яка проявлялась як незрозуміла 'dropped the reply channel'); request() у acp-kit.js журналить провал спавну сесії як 'failed' замість непійманого throw
|
|
8
|
+
|
|
9
|
+
## [0.13.6] - 2026-07-20
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- AgentDialog: перемикання агента mid-conversation тепер зберігає видимий чат-лог і передає новому агенту текстовий дайджест попередньої розмови як контекст, замість повного скидання
|
|
14
|
+
|
|
3
15
|
## [0.13.5] - 2026-07-20
|
|
4
16
|
|
|
5
17
|
### Fixed
|
package/package.json
CHANGED
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
<div v-if="turns.length" ref="logEl" class="chat-log">
|
|
31
31
|
<template v-for="(turn, i) in turns" :key="i">
|
|
32
32
|
<div v-if="turn.role === 'user'" class="chat-user">{{ turn.text }}</div>
|
|
33
|
+
<div v-else-if="turn.role === 'switch'" class="chat-switch">→ {{ turn.label }}</div>
|
|
33
34
|
<template v-else>
|
|
34
35
|
<div class="chat-model-label">{{ turn.agentLabel }}</div>
|
|
35
36
|
<RequestView :result="turn.result" />
|
|
@@ -151,18 +152,40 @@ function apply(outcome) {
|
|
|
151
152
|
scrollToEnd()
|
|
152
153
|
}
|
|
153
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Render the transcript so far as plain text, for handing off to a freshly
|
|
157
|
+
* spawned agent that's replacing whichever one the conversation started
|
|
158
|
+
* with — a new ACP session has no memory of it otherwise.
|
|
159
|
+
* @returns {string} context block, or '' when there's nothing to hand off
|
|
160
|
+
*/
|
|
161
|
+
function handoffContext() {
|
|
162
|
+
const relevant = turns.value.filter(turn => turn.role !== 'switch')
|
|
163
|
+
if (!relevant.length) return ''
|
|
164
|
+
const lines = relevant.map(turn =>
|
|
165
|
+
turn.role === 'user'
|
|
166
|
+
? `Користувач: ${turn.text}`
|
|
167
|
+
: `Агент (${turn.agentLabel}): ${turn.result?.summary ?? turn.result?.question ?? ''}`
|
|
168
|
+
)
|
|
169
|
+
return `Контекст попередньої розмови (продовжуєш замість іншого агента):\n${lines.join('\n')}\n\nНове повідомлення:\n`
|
|
170
|
+
}
|
|
171
|
+
|
|
154
172
|
/**
|
|
155
173
|
* Send the current message: start a new request, or resume the conversation
|
|
156
174
|
* — unless the agent/tier dropdowns have moved away from whichever agent
|
|
157
|
-
* spawned the active session, in which case restart as a fresh
|
|
175
|
+
* spawned the active session, in which case restart as a fresh ACP session
|
|
158
176
|
* (equivalent to closing and reopening the dialog) so the new message
|
|
159
|
-
* actually goes to the newly selected agent.
|
|
177
|
+
* actually goes to the newly selected agent. The visible transcript keeps
|
|
178
|
+
* growing across the switch, and the prior turns are prepended as plain-text
|
|
179
|
+
* context to the new agent's first message so it can actually continue the
|
|
180
|
+
* conversation rather than starting blind.
|
|
160
181
|
*/
|
|
161
182
|
async function send() {
|
|
162
183
|
const text = prompt.value.trim()
|
|
163
184
|
if (!text || running.value) return
|
|
164
|
-
|
|
165
|
-
|
|
185
|
+
const switching = Boolean(requestId.value) && currentSpawnKey() !== activeSpawnKey.value
|
|
186
|
+
const payload = switching ? `${handoffContext()}${text}` : text
|
|
187
|
+
if (switching) {
|
|
188
|
+
turns.value.push({ role: 'switch', label: currentAgentLabel() })
|
|
166
189
|
requestId.value = null
|
|
167
190
|
}
|
|
168
191
|
prompt.value = ''
|
|
@@ -177,7 +200,7 @@ async function send() {
|
|
|
177
200
|
activeAgentLabel.value = currentAgentLabel()
|
|
178
201
|
activeSpawnKey.value = currentSpawnKey()
|
|
179
202
|
}
|
|
180
|
-
apply(await (requestId.value ? respond(requestId.value,
|
|
203
|
+
apply(await (requestId.value ? respond(requestId.value, payload) : request(payload)))
|
|
181
204
|
} catch (error) {
|
|
182
205
|
$q.notify({ type: 'negative', message: String(error?.message ?? error) })
|
|
183
206
|
} finally {
|
|
@@ -217,6 +240,14 @@ async function send() {
|
|
|
217
240
|
margin-bottom: -4px;
|
|
218
241
|
}
|
|
219
242
|
|
|
243
|
+
.chat-switch {
|
|
244
|
+
align-self: center;
|
|
245
|
+
font-size: 11px;
|
|
246
|
+
opacity: 0.55;
|
|
247
|
+
text-transform: uppercase;
|
|
248
|
+
letter-spacing: 0.02em;
|
|
249
|
+
}
|
|
250
|
+
|
|
220
251
|
.chat-thinking {
|
|
221
252
|
display: flex;
|
|
222
253
|
align-items: center;
|
package/src/core/acp-kit.js
CHANGED
|
@@ -125,6 +125,28 @@ export function createAcpAgentKit({
|
|
|
125
125
|
await deps.onAcpPermissionRequest(handlePermissionRequest)
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Journal a request as failed and return its structured result envelope —
|
|
130
|
+
* shared by a session that never spawned and a turn that errored mid-flight.
|
|
131
|
+
* @param {string} requestId journal record id
|
|
132
|
+
* @param {object[]} baseActions actions already recorded for this request
|
|
133
|
+
* @param {unknown} error the thrown/rejected value
|
|
134
|
+
* @returns {Promise<object>} structured result envelope
|
|
135
|
+
*/
|
|
136
|
+
async function failedResult(requestId, baseActions, error) {
|
|
137
|
+
const message = String(error?.message ?? error)
|
|
138
|
+
await journal.update(requestId, { status: 'failed', error: message })
|
|
139
|
+
return {
|
|
140
|
+
requestId,
|
|
141
|
+
status: 'failed',
|
|
142
|
+
summary: null,
|
|
143
|
+
error: message,
|
|
144
|
+
actions: baseActions,
|
|
145
|
+
question: null,
|
|
146
|
+
pendingApproval: null
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
128
150
|
/**
|
|
129
151
|
* Run one turn, journal the result, and reset `pendingApproval`. Callers
|
|
130
152
|
* must set `activeRequestId` themselves *before* starting the turn — a
|
|
@@ -141,17 +163,7 @@ export function createAcpAgentKit({
|
|
|
141
163
|
try {
|
|
142
164
|
turn = await turnPromise
|
|
143
165
|
} catch (error) {
|
|
144
|
-
|
|
145
|
-
await journal.update(requestId, { status: 'failed', error: message })
|
|
146
|
-
return {
|
|
147
|
-
requestId,
|
|
148
|
-
status: 'failed',
|
|
149
|
-
summary: null,
|
|
150
|
-
error: message,
|
|
151
|
-
actions: baseActions,
|
|
152
|
-
question: null,
|
|
153
|
-
pendingApproval: null
|
|
154
|
-
}
|
|
166
|
+
return failedResult(requestId, baseActions, error)
|
|
155
167
|
}
|
|
156
168
|
const fields = finalizeTurn(turn)
|
|
157
169
|
const actions = [...baseActions, ...turn.trace]
|
|
@@ -170,7 +182,12 @@ export function createAcpAgentKit({
|
|
|
170
182
|
await ensureListening()
|
|
171
183
|
const id = await journal.create({ intent, actor: AGENT_ACTOR })
|
|
172
184
|
await journal.update(id, { status: 'running' })
|
|
173
|
-
|
|
185
|
+
let session
|
|
186
|
+
try {
|
|
187
|
+
session = await deps.createAcpSession(agent)
|
|
188
|
+
} catch (error) {
|
|
189
|
+
return failedResult(id, [], error)
|
|
190
|
+
}
|
|
174
191
|
activeSessionKey = session.sessionKey
|
|
175
192
|
activeRequestId = id
|
|
176
193
|
await journal.update(id, { acp: { agentKind: session.agentKind, sessionKey: session.sessionKey } })
|