@agentshouse/kit 0.2.1-c0b0ffa6c025b → 0.2.1-c0eea939ba749
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 +14 -14
- package/dist/acp.js +34 -14
- package/dist/agents.js +50 -17
- package/dist/api.js +1 -1
- package/dist/app-git.js +10 -26
- package/dist/bootstrap.json +4 -4
- package/dist/bridge.js +3 -6
- package/dist/chatgpt.js +4 -1
- package/dist/clis.js +9 -0
- package/dist/conversations.js +123 -72
- package/dist/copies.js +86 -45
- package/dist/end.js +3 -2
- package/dist/events.js +4 -0
- package/dist/files.js +1 -1
- package/dist/git.js +2 -3
- package/dist/home.js +27 -13
- package/dist/house-cli.js +291 -0
- package/dist/house-main.js +7 -289
- package/dist/inputs.js +37 -0
- package/dist/instructions.js +2 -1
- package/dist/kit-cli.js +68 -0
- package/dist/kit-main.js +8 -67
- package/dist/login.js +14 -5
- package/dist/logout.js +0 -2
- package/dist/placement.js +2 -20
- package/dist/resident.js +60 -15
- package/dist/service.js +22 -0
- package/dist/sign-in.js +5 -23
- package/dist/stream.js +5 -5
- package/dist/update.js +20 -23
- package/dist/wire.js +1 -1
- package/dist/work.js +3 -5
- package/package.json +1 -1
package/dist/conversations.js
CHANGED
|
@@ -1,22 +1,50 @@
|
|
|
1
|
-
import { client, } from '@agentclientprotocol/sdk';
|
|
1
|
+
import { client, RequestError, } from '@agentclientprotocol/sdk';
|
|
2
2
|
import { createHash, randomUUID } from 'node:crypto';
|
|
3
3
|
import { mkdir } from 'node:fs/promises';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import { unlessAborted } from './abort.js';
|
|
6
6
|
import { startAdapter } from './acp.js';
|
|
7
|
+
import { finalRefusal } from './api.js';
|
|
7
8
|
import { openBridge } from './bridge.js';
|
|
8
9
|
import { CLIS } from './clis.js';
|
|
9
|
-
import { readerFor } from './events.js';
|
|
10
|
+
import { answeredFailure, readerFor } from './events.js';
|
|
10
11
|
import { placeFiles, uploadBytes } from './files.js';
|
|
11
12
|
import { agentBase } from './home.js';
|
|
12
13
|
import { instructions } from './instructions.js';
|
|
13
14
|
import { Parts } from './parts.js';
|
|
15
|
+
import { refusalOf } from './refusals.js';
|
|
14
16
|
import { killMarked, Scope } from './scope.js';
|
|
15
17
|
import { holdSecretInput } from './secret-input.js';
|
|
16
18
|
import { createHowWeWork } from './skills.js';
|
|
17
19
|
import { transcribe } from './transcription.js';
|
|
18
20
|
import { workFor } from './work.js';
|
|
21
|
+
const SIGNED_OUT = RequestError.authRequired().code;
|
|
19
22
|
const KILLED = 'the conversation was killed';
|
|
23
|
+
const REFUSED = 'the CLI refused the prompt';
|
|
24
|
+
const NO_CONNECTION = "the Agent's computer could not open this conversation; try again";
|
|
25
|
+
const GONE = 'House no longer holds this conversation; start a new one';
|
|
26
|
+
const RETIRED = "this conversation's Agent is retired, so it cannot start";
|
|
27
|
+
const ENDED = {
|
|
28
|
+
conversation_not_found: GONE,
|
|
29
|
+
conversation_historical: RETIRED,
|
|
30
|
+
};
|
|
31
|
+
const NO_START = "the Agent's CLI did not start";
|
|
32
|
+
const NO_SESSION = "the Agent's CLI did not open a session";
|
|
33
|
+
const NO_RESUME = "the Agent's CLI could not resume this conversation";
|
|
34
|
+
const NO_SETTINGS = "the Agent's CLI refused the Agent's model, mode or effort";
|
|
35
|
+
class NotStarted extends Error {
|
|
36
|
+
}
|
|
37
|
+
async function step(reason, work) {
|
|
38
|
+
try {
|
|
39
|
+
return await work;
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
throw new NotStarted(typeof reason === 'string' ? reason : reason(error), { cause: error });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function unbridged(error) {
|
|
46
|
+
return (finalRefusal(error) ? ENDED[refusalOf(error.text)?.code ?? ''] : undefined) ?? NO_CONNECTION;
|
|
47
|
+
}
|
|
20
48
|
const EXIT_PLAN_MODE = {
|
|
21
49
|
parse(value) {
|
|
22
50
|
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
@@ -29,19 +57,32 @@ export const CONVERSATION_INPUTS = new Set(['open', 'message', 'interrupt', 'kil
|
|
|
29
57
|
function causeOf(error) {
|
|
30
58
|
return error instanceof Error ? error.message : String(error);
|
|
31
59
|
}
|
|
60
|
+
function answeredWith(error) {
|
|
61
|
+
const signedOut = typeof error === 'object' && error !== null && error.code === SIGNED_OUT;
|
|
62
|
+
return { failure: signedOut ? 'signed_out' : 'error', cause: causeOf(error) };
|
|
63
|
+
}
|
|
64
|
+
function exitedWith(running, cause) {
|
|
65
|
+
return running.killed ? { failure: 'killed', cause: KILLED } : { failure: 'exited', cause };
|
|
66
|
+
}
|
|
32
67
|
function answerMessage(request, response) {
|
|
33
68
|
return `The User answered a question you asked earlier.\nQuestion: ${JSON.stringify(request)}\nAnswer: ${JSON.stringify(response)}`;
|
|
34
69
|
}
|
|
35
70
|
function logged(error) {
|
|
36
71
|
process.stderr.write(`kit: ${causeOf(error)}\n`);
|
|
37
72
|
}
|
|
73
|
+
function refusal(conversation, error) {
|
|
74
|
+
if (conversation.kills > 0)
|
|
75
|
+
return KILLED;
|
|
76
|
+
const cause = error instanceof NotStarted ? `${error.message}: ${causeOf(error.cause)}` : causeOf(error);
|
|
77
|
+
logged(new Error(`conversation ${conversation.id} did not start: ${cause}`));
|
|
78
|
+
return causeOf(error);
|
|
79
|
+
}
|
|
38
80
|
function marker(bridge) {
|
|
39
81
|
return `HOUSE_BRIDGE=${bridge.env.HOUSE_BRIDGE}`;
|
|
40
82
|
}
|
|
41
83
|
class Turn {
|
|
42
84
|
id = randomUUID();
|
|
43
85
|
parts;
|
|
44
|
-
admitted = false;
|
|
45
86
|
questions = 0;
|
|
46
87
|
secrets = 0;
|
|
47
88
|
prompted = false;
|
|
@@ -65,6 +106,7 @@ class Conversation {
|
|
|
65
106
|
subagents = new Map();
|
|
66
107
|
held = [];
|
|
67
108
|
opening = null;
|
|
109
|
+
prompted = null;
|
|
68
110
|
kills = 0;
|
|
69
111
|
killed = new AbortController();
|
|
70
112
|
interrupts = 0;
|
|
@@ -87,9 +129,7 @@ function asksSecret(request) {
|
|
|
87
129
|
export class Conversations {
|
|
88
130
|
kit;
|
|
89
131
|
conversations = new Map();
|
|
90
|
-
acks = new Map();
|
|
91
132
|
questions = new Map();
|
|
92
|
-
carrying = 0;
|
|
93
133
|
reporting = 0;
|
|
94
134
|
watched = false;
|
|
95
135
|
constructor(kit) {
|
|
@@ -98,37 +138,26 @@ export class Conversations {
|
|
|
98
138
|
setInterval(() => this.look(), 2_000);
|
|
99
139
|
}
|
|
100
140
|
input(input) {
|
|
101
|
-
this.
|
|
102
|
-
|
|
103
|
-
(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
conversation.queue = handled.catch(() => undefined);
|
|
118
|
-
const work = handled.then(({ ack }) => ack);
|
|
119
|
-
this.acks.set(input.input_id, work);
|
|
120
|
-
return work;
|
|
121
|
-
})();
|
|
122
|
-
carried
|
|
123
|
-
.then((body) => this.kit.house.deliver(`/kit/inputs/${input.input_id}/ack`, body))
|
|
124
|
-
.catch(logged)
|
|
125
|
-
.finally(() => {
|
|
126
|
-
this.carrying--;
|
|
127
|
-
this.kit.changed();
|
|
141
|
+
void this.kit.inputs.carry(input.input_id, () => {
|
|
142
|
+
const conversation = this.conversation(input.conversation_id);
|
|
143
|
+
if (input.kind === 'kill') {
|
|
144
|
+
conversation.kills++;
|
|
145
|
+
conversation.killed.abort(new Error(KILLED));
|
|
146
|
+
for (const waiting of conversation.waiting.splice(0))
|
|
147
|
+
waiting.settle({ refused: KILLED });
|
|
148
|
+
this.halt(conversation);
|
|
149
|
+
}
|
|
150
|
+
if (input.kind === 'interrupt') {
|
|
151
|
+
conversation.interrupts++;
|
|
152
|
+
conversation.interrupted.abort();
|
|
153
|
+
}
|
|
154
|
+
const handled = conversation.queue.then(() => this.carry(conversation, input));
|
|
155
|
+
conversation.queue = handled.catch(() => undefined);
|
|
156
|
+
return handled.then(async ({ ack }) => ({ ack: await ack }));
|
|
128
157
|
});
|
|
129
158
|
}
|
|
130
159
|
idle() {
|
|
131
|
-
if (this.
|
|
160
|
+
if (this.reporting > 0)
|
|
132
161
|
return false;
|
|
133
162
|
for (const conversation of this.conversations.values()) {
|
|
134
163
|
const turn = conversation.turn;
|
|
@@ -208,10 +237,10 @@ export class Conversations {
|
|
|
208
237
|
if (conversation.running !== null)
|
|
209
238
|
return {};
|
|
210
239
|
try {
|
|
211
|
-
return { provider_session_id: await this.start(conversation, await this.route(conversation, input.agent_id), null) };
|
|
240
|
+
return { provider_session_id: await this.start(conversation, await this.route(conversation, input.agent_id), null, true) };
|
|
212
241
|
}
|
|
213
242
|
catch (error) {
|
|
214
|
-
return { refused:
|
|
243
|
+
return { refused: refusal(conversation, error) };
|
|
215
244
|
}
|
|
216
245
|
}
|
|
217
246
|
async message(conversation, input) {
|
|
@@ -228,7 +257,7 @@ export class Conversations {
|
|
|
228
257
|
throw new Error(KILLED);
|
|
229
258
|
}
|
|
230
259
|
catch (error) {
|
|
231
|
-
return { ack: Promise.resolve({ refused: conversation
|
|
260
|
+
return { ack: Promise.resolve({ refused: refusal(conversation, error) }) };
|
|
232
261
|
}
|
|
233
262
|
return {
|
|
234
263
|
ack: new Promise((settle) => {
|
|
@@ -251,13 +280,17 @@ export class Conversations {
|
|
|
251
280
|
async send(conversation, waiting) {
|
|
252
281
|
const { input } = waiting;
|
|
253
282
|
let ack = {};
|
|
283
|
+
let started = false;
|
|
254
284
|
const prompt = [];
|
|
255
285
|
try {
|
|
256
286
|
if (conversation.running === null) {
|
|
257
|
-
const
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
287
|
+
const stored = conversation.session ?? input.provider_session_id;
|
|
288
|
+
const empty = input.first === true && conversation.prompted !== stored;
|
|
289
|
+
started = (await this.start(conversation, waiting.route, stored, empty)) !== stored;
|
|
290
|
+
}
|
|
291
|
+
const session = conversation.running.sessionId;
|
|
292
|
+
if (started || (input.first === true && session !== input.provider_session_id)) {
|
|
293
|
+
ack = { provider_session_id: session };
|
|
261
294
|
}
|
|
262
295
|
if (input.first === true) {
|
|
263
296
|
prompt.push({
|
|
@@ -269,11 +302,11 @@ export class Conversations {
|
|
|
269
302
|
throw new Error(KILLED);
|
|
270
303
|
}
|
|
271
304
|
catch (error) {
|
|
272
|
-
if (
|
|
305
|
+
if (started) {
|
|
273
306
|
conversation.session = null;
|
|
274
307
|
await this.kill(conversation);
|
|
275
308
|
}
|
|
276
|
-
waiting.settle({ refused: conversation
|
|
309
|
+
waiting.settle({ refused: refusal(conversation, error) });
|
|
277
310
|
return;
|
|
278
311
|
}
|
|
279
312
|
this.prompt(conversation, [...prompt, ...waiting.content]);
|
|
@@ -351,7 +384,7 @@ export class Conversations {
|
|
|
351
384
|
}
|
|
352
385
|
return route;
|
|
353
386
|
}
|
|
354
|
-
async start(conversation, route, sessionId) {
|
|
387
|
+
async start(conversation, route, sessionId, empty) {
|
|
355
388
|
const reader = readerFor(route.kind);
|
|
356
389
|
reader.session = sessionId;
|
|
357
390
|
const app = client({ name: '@agentshouse/kit' })
|
|
@@ -359,7 +392,7 @@ export class Conversations {
|
|
|
359
392
|
.onRequest('elicitation/create', ({ params, signal }) => this.ask(conversation, 'elicitation/create', params, asksSecret(params), signal))
|
|
360
393
|
.onRequest('_x.ai/exit_plan_mode', EXIT_PLAN_MODE, ({ params, signal }) => this.ask(conversation, '_x.ai/exit_plan_mode', params, false, signal));
|
|
361
394
|
const cli = await unlessAborted(this.kit.agents.cli(route.kind), conversation.killed.signal);
|
|
362
|
-
const bridge = await openBridge(this.kit.house, this.kit.copies, conversation.id, conversation.killed.signal);
|
|
395
|
+
const bridge = await step(unbridged, openBridge(this.kit.house, this.kit.copies, conversation.id, conversation.killed.signal));
|
|
363
396
|
if (conversation.kills > 0) {
|
|
364
397
|
bridge.close();
|
|
365
398
|
throw new Error(KILLED);
|
|
@@ -367,27 +400,28 @@ export class Conversations {
|
|
|
367
400
|
conversation.opening = bridge;
|
|
368
401
|
const work = workFor(route.kind, route.working_directory, () => this.kit.changed());
|
|
369
402
|
const scope = new Scope(marker(bridge), randomUUID(), cli);
|
|
403
|
+
let adapter = null;
|
|
370
404
|
try {
|
|
371
405
|
await unlessAborted(createHowWeWork(bridge), conversation.killed.signal);
|
|
372
406
|
await CLIS[route.kind].allowHouse(bridge.env.PATH);
|
|
373
|
-
const
|
|
407
|
+
const streamed = await step(NO_CONNECTION, work.open(cli));
|
|
408
|
+
adapter = await step(NO_START, startAdapter(route.kind, cli, route.working_directory, app, (message) => {
|
|
374
409
|
work.read(message);
|
|
375
410
|
this.read(conversation, reader, message);
|
|
376
|
-
}, { ...bridge.env, ...
|
|
411
|
+
}, { ...bridge.env, ...streamed }, undefined, scope));
|
|
377
412
|
void adapter.exited.then(() => bridge.close());
|
|
378
413
|
const agent = adapter.connection.agent;
|
|
379
414
|
const cwd = route.working_directory;
|
|
380
415
|
const _meta = CLIS[route.kind].sessionMeta(bridge.env.HOUSE_BRIDGE, conversation.id);
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
: { ...(await agent.request('session/resume', { sessionId, cwd, mcpServers: [], _meta })), sessionId };
|
|
416
|
+
const resumed = sessionId === null ? null : await this.resume(conversation, route.kind, adapter, { sessionId, cwd, mcpServers: [], _meta }, empty);
|
|
417
|
+
const opened = resumed ?? (await step(NO_SESSION, agent.request('session/new', { cwd, mcpServers: [], _meta })));
|
|
384
418
|
reader.session = opened.sessionId;
|
|
385
|
-
if (sessionId
|
|
419
|
+
if (opened.sessionId !== sessionId && CLIS[route.kind].renames) {
|
|
386
420
|
const prompt = [{ type: 'text', text: `/rename ${conversation.id}` }];
|
|
387
|
-
await agent.request('session/prompt', { sessionId: opened.sessionId, prompt });
|
|
421
|
+
await step(NO_SESSION, agent.request('session/prompt', { sessionId: opened.sessionId, prompt }));
|
|
388
422
|
}
|
|
389
423
|
const running = { adapter, bridge, sessionId: opened.sessionId, killed: false, reader, work, scope };
|
|
390
|
-
const options = await this.launchSettings(running, route, opened.configOptions ?? []);
|
|
424
|
+
const options = await step(NO_SETTINGS, this.launchSettings(running, route, opened.configOptions ?? []));
|
|
391
425
|
void work.settled().then(() => scope.record());
|
|
392
426
|
conversation.running = running;
|
|
393
427
|
conversation.session = running.sessionId;
|
|
@@ -395,11 +429,11 @@ export class Conversations {
|
|
|
395
429
|
if (conversation.commands !== null)
|
|
396
430
|
this.commands(conversation, conversation.commands);
|
|
397
431
|
this.options(conversation, options);
|
|
398
|
-
void adapter.
|
|
432
|
+
void adapter.lost.then((cause) => this.exited(conversation, running, cause));
|
|
399
433
|
return running.sessionId;
|
|
400
434
|
}
|
|
401
435
|
catch (error) {
|
|
402
|
-
|
|
436
|
+
adapter?.retire();
|
|
403
437
|
work.close();
|
|
404
438
|
conversation.leftovers.add(scope);
|
|
405
439
|
bridge.close();
|
|
@@ -409,6 +443,18 @@ export class Conversations {
|
|
|
409
443
|
conversation.opening = null;
|
|
410
444
|
}
|
|
411
445
|
}
|
|
446
|
+
async resume(conversation, kind, adapter, request, empty) {
|
|
447
|
+
try {
|
|
448
|
+
return { ...(await adapter.connection.agent.request('session/resume', request)), sessionId: request.sessionId };
|
|
449
|
+
}
|
|
450
|
+
catch (error) {
|
|
451
|
+
if (!empty || conversation.kills > 0 || !CLIS[kind].unknownSession(error)) {
|
|
452
|
+
throw new NotStarted(NO_RESUME, { cause: error });
|
|
453
|
+
}
|
|
454
|
+
logged(new Error(`conversation ${conversation.id} opens a new session: ${NO_RESUME}: ${causeOf(error)}`));
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
412
458
|
async launchSettings(running, route, offered) {
|
|
413
459
|
let options = offered;
|
|
414
460
|
const settings = [
|
|
@@ -430,13 +476,10 @@ export class Conversations {
|
|
|
430
476
|
}
|
|
431
477
|
return options;
|
|
432
478
|
}
|
|
433
|
-
exited(conversation,
|
|
434
|
-
const running = conversation.running;
|
|
435
|
-
if (running?.adapter !== adapter)
|
|
436
|
-
return;
|
|
479
|
+
exited(conversation, running, cause) {
|
|
437
480
|
this.detach(conversation, running);
|
|
438
481
|
if (conversation.turn !== null) {
|
|
439
|
-
this.end(conversation, conversation.turn,
|
|
482
|
+
this.end(conversation, conversation.turn, exitedWith(running, cause));
|
|
440
483
|
}
|
|
441
484
|
this.next(conversation);
|
|
442
485
|
this.kit.changed();
|
|
@@ -475,7 +518,7 @@ export class Conversations {
|
|
|
475
518
|
return delivered;
|
|
476
519
|
}
|
|
477
520
|
write(conversation, turn, operation) {
|
|
478
|
-
if (
|
|
521
|
+
if (turn.ended || !this.watched)
|
|
479
522
|
return;
|
|
480
523
|
this.kit.send({ type: 'turn', conversation_id: conversation.id, turn_id: turn.id, ...operation });
|
|
481
524
|
}
|
|
@@ -486,12 +529,7 @@ export class Conversations {
|
|
|
486
529
|
begin(conversation) {
|
|
487
530
|
const turn = new Turn((operation) => this.write(conversation, turn, operation));
|
|
488
531
|
conversation.open++;
|
|
489
|
-
void this.deliver(conversation, turn, 'started', {})
|
|
490
|
-
.then(() => {
|
|
491
|
-
turn.admitted = true;
|
|
492
|
-
this.replay(conversation, turn);
|
|
493
|
-
})
|
|
494
|
-
.catch(logged);
|
|
532
|
+
void this.deliver(conversation, turn, 'started', {}).catch(logged);
|
|
495
533
|
conversation.turn = turn;
|
|
496
534
|
if (conversation.context !== null)
|
|
497
535
|
turn.parts.measure(conversation.context);
|
|
@@ -500,13 +538,17 @@ export class Conversations {
|
|
|
500
538
|
this.kit.changed();
|
|
501
539
|
return turn;
|
|
502
540
|
}
|
|
503
|
-
end(conversation, turn, failed) {
|
|
541
|
+
end(conversation, turn, failed, notice = null) {
|
|
504
542
|
if (turn.ended)
|
|
505
543
|
return;
|
|
544
|
+
if (failed !== null)
|
|
545
|
+
logged(new Error(`conversation ${conversation.id} turn ${turn.id} failed: ${failed.cause}`));
|
|
506
546
|
if (conversation.turn === turn) {
|
|
507
547
|
for (const event of conversation.running?.reader.closeTurn() ?? [])
|
|
508
548
|
this.apply(conversation, turn, event);
|
|
509
549
|
}
|
|
550
|
+
if (notice !== null)
|
|
551
|
+
turn.parts.start({ type: 'marker', marker: 'retry', text: notice });
|
|
510
552
|
turn.ended = true;
|
|
511
553
|
conversation.open--;
|
|
512
554
|
if (conversation.turn === turn)
|
|
@@ -514,7 +556,7 @@ export class Conversations {
|
|
|
514
556
|
const body = Promise.allSettled(turn.uploads).then(() => ({
|
|
515
557
|
parts: turn.parts.saved(),
|
|
516
558
|
context: turn.parts.context,
|
|
517
|
-
...failed,
|
|
559
|
+
...(failed === null ? {} : { failed: failed.failure }),
|
|
518
560
|
}));
|
|
519
561
|
void this.deliver(conversation, turn, 'ended', body).catch(logged);
|
|
520
562
|
this.next(conversation);
|
|
@@ -524,16 +566,25 @@ export class Conversations {
|
|
|
524
566
|
const running = conversation.running;
|
|
525
567
|
const turn = this.begin(conversation);
|
|
526
568
|
turn.prompted = true;
|
|
527
|
-
|
|
569
|
+
conversation.prompted = running.sessionId;
|
|
570
|
+
running.adapter.connection.agent.request('session/prompt', { sessionId: running.sessionId, prompt }).then((answer) => {
|
|
571
|
+
const notice = answeredFailure(answer);
|
|
572
|
+
if (notice !== null) {
|
|
573
|
+
this.end(conversation, turn, { failure: notice.limit ? 'limit' : 'error', cause: notice.title }, notice.title);
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
this.end(conversation, turn, answer.stopReason === 'refusal' ? { failure: 'refused', cause: REFUSED } : null);
|
|
577
|
+
}
|
|
578
|
+
}, async (error) => {
|
|
528
579
|
if (running.adapter.connection.signal.aborted) {
|
|
529
|
-
this.end(conversation, turn,
|
|
580
|
+
this.end(conversation, turn, exitedWith(running, await running.adapter.exited));
|
|
530
581
|
}
|
|
531
582
|
else {
|
|
532
583
|
if (conversation.open === 1 && conversation.running === running) {
|
|
533
|
-
running.
|
|
584
|
+
running.adapter.retire();
|
|
534
585
|
this.detach(conversation, running);
|
|
535
586
|
}
|
|
536
|
-
this.end(conversation, turn,
|
|
587
|
+
this.end(conversation, turn, answeredWith(error));
|
|
537
588
|
}
|
|
538
589
|
});
|
|
539
590
|
}
|