blun-king-cli 9.1.462 → 9.1.464
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/bin/agent-api-runtime.mjs +252 -0
- package/bin/agent-api-tool-broker.cjs +248 -0
- package/bin/profile-runtime.cjs +54 -0
- package/bin/session-replay-window-policy.cjs +22 -0
- package/bin/session-scrollback-archive.cjs +23 -0
- package/bin/subagent-parent-responsiveness.cjs +19 -0
- package/bin/telegram-addressed-focus.cjs +45 -0
- package/blun.mjs +126 -28
- package/package.json +1 -1
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
const { createAgentApiToolBroker } = require('./agent-api-tool-broker.cjs');
|
|
6
|
+
|
|
7
|
+
const CLIENT_TOOL_NAME_PATTERN = /^[A-Za-z0-9_-]{1,64}$/u;
|
|
8
|
+
const INTERNAL_TOOL_PREFIX = 'client__';
|
|
9
|
+
const NO_CLIENT_TOOLS_PREFIX = '__blun_agent_api_no_client_tools__';
|
|
10
|
+
|
|
11
|
+
class AgentApiRuntimeError extends Error {
|
|
12
|
+
constructor(code, message) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = 'AgentApiRuntimeError';
|
|
15
|
+
this.code = code;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function runtimeError(code, message) {
|
|
20
|
+
return new AgentApiRuntimeError(code, message);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function requireId(value, label) {
|
|
24
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
25
|
+
throw runtimeError('AGENT_API_INVALID_SCOPE', `${label} must be a non-empty string`);
|
|
26
|
+
}
|
|
27
|
+
return value.trim();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function cloneStructured(value, label) {
|
|
31
|
+
try {
|
|
32
|
+
return structuredClone(value);
|
|
33
|
+
} catch {
|
|
34
|
+
throw runtimeError(
|
|
35
|
+
'AGENT_API_INVALID_TOOL_DEFINITION',
|
|
36
|
+
`${label} must be structured-cloneable`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function normalizeParameters(value, name) {
|
|
42
|
+
if (value === undefined) {
|
|
43
|
+
return { type: 'object', properties: {} };
|
|
44
|
+
}
|
|
45
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
46
|
+
throw runtimeError(
|
|
47
|
+
'AGENT_API_INVALID_TOOL_DEFINITION',
|
|
48
|
+
`tool "${name}" parameters must be an object`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
return cloneStructured(value, `tool "${name}" parameters`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function normalizeClientToolDefinitions(tools) {
|
|
55
|
+
if (!Array.isArray(tools)) {
|
|
56
|
+
throw runtimeError('AGENT_API_INVALID_TOOLS', 'tools must be an array');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const names = new Set();
|
|
60
|
+
return tools.map((tool, index) => {
|
|
61
|
+
if (tool === null || typeof tool !== 'object' || Array.isArray(tool)
|
|
62
|
+
|| tool.type !== 'function'
|
|
63
|
+
|| tool.function === null
|
|
64
|
+
|| typeof tool.function !== 'object'
|
|
65
|
+
|| Array.isArray(tool.function)) {
|
|
66
|
+
throw runtimeError(
|
|
67
|
+
'AGENT_API_INVALID_TOOL_DEFINITION',
|
|
68
|
+
`tools[${index}] must be an OpenAI function tool`,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const name = tool.function.name;
|
|
73
|
+
if (typeof name !== 'string' || !CLIENT_TOOL_NAME_PATTERN.test(name)) {
|
|
74
|
+
throw runtimeError(
|
|
75
|
+
'AGENT_API_INVALID_TOOL_DEFINITION',
|
|
76
|
+
`tools[${index}].function.name must match ${CLIENT_TOOL_NAME_PATTERN}`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
if (names.has(name)) {
|
|
80
|
+
throw runtimeError(
|
|
81
|
+
'AGENT_API_DUPLICATE_TOOL_NAME',
|
|
82
|
+
`tool name "${name}" is declared more than once`,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
names.add(name);
|
|
86
|
+
|
|
87
|
+
const description = tool.function.description;
|
|
88
|
+
if (description !== undefined && typeof description !== 'string') {
|
|
89
|
+
throw runtimeError(
|
|
90
|
+
'AGENT_API_INVALID_TOOL_DEFINITION',
|
|
91
|
+
`tool "${name}" description must be a string`,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return Object.freeze({
|
|
96
|
+
name,
|
|
97
|
+
description: description ?? '',
|
|
98
|
+
parameters: normalizeParameters(tool.function.parameters, name),
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function shortHash(value, length = 10) {
|
|
104
|
+
return createHash('sha256').update(value).digest('hex').slice(0, length);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function internalToolName(publicName, index) {
|
|
108
|
+
const ordinal = index.toString(36).padStart(2, '0');
|
|
109
|
+
const prefix = `${INTERNAL_TOOL_PREFIX}${ordinal}__`;
|
|
110
|
+
const suffix = `__${shortHash(publicName, 8)}`;
|
|
111
|
+
const available = 64 - prefix.length - suffix.length;
|
|
112
|
+
return `${prefix}${publicName.slice(0, available)}${suffix}`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function noClientToolsSentinel(sessionId, requestId) {
|
|
116
|
+
return `${NO_CLIENT_TOOLS_PREFIX}${shortHash(`${sessionId}\0${requestId}`, 16)}`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function validateSession(session) {
|
|
120
|
+
if (session === null || typeof session !== 'object') {
|
|
121
|
+
throw runtimeError('AGENT_API_INVALID_SESSION', 'session must be an SDK session');
|
|
122
|
+
}
|
|
123
|
+
const requiredMethods = [
|
|
124
|
+
'registerToolAndWait',
|
|
125
|
+
'unregisterToolAndWait',
|
|
126
|
+
'setAllowedTools',
|
|
127
|
+
];
|
|
128
|
+
for (const method of requiredMethods) {
|
|
129
|
+
if (typeof session[method] !== 'function') {
|
|
130
|
+
throw runtimeError(
|
|
131
|
+
'AGENT_API_INVALID_SESSION',
|
|
132
|
+
`session.${method} must be a function`,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return requireId(session.id, 'session.id');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async function unregisterTools(session, names) {
|
|
140
|
+
let firstError;
|
|
141
|
+
for (const name of [...names].reverse()) {
|
|
142
|
+
try {
|
|
143
|
+
await session.unregisterToolAndWait(name);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
firstError ??= error;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (firstError !== undefined) throw firstError;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function createAgentApiRuntime(options = {}) {
|
|
152
|
+
const broker = options.broker ?? createAgentApiToolBroker(options.brokerOptions);
|
|
153
|
+
|
|
154
|
+
async function bindClientTools(input) {
|
|
155
|
+
if (input === null || typeof input !== 'object') {
|
|
156
|
+
throw runtimeError('AGENT_API_INVALID_REQUEST', 'binding input must be an object');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const sessionId = validateSession(input.session);
|
|
160
|
+
const requestId = requireId(input.requestId, 'requestId');
|
|
161
|
+
const tools = normalizeClientToolDefinitions(input.tools ?? []);
|
|
162
|
+
const mappings = tools.map((tool, index) => Object.freeze({
|
|
163
|
+
...tool,
|
|
164
|
+
internalName: internalToolName(tool.name, index),
|
|
165
|
+
}));
|
|
166
|
+
const registeredNames = [];
|
|
167
|
+
|
|
168
|
+
broker.beginRequest({
|
|
169
|
+
sessionId,
|
|
170
|
+
requestId,
|
|
171
|
+
toolNames: mappings.map((tool) => tool.name),
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
for (const tool of mappings) {
|
|
176
|
+
await input.session.registerToolAndWait(
|
|
177
|
+
tool.internalName,
|
|
178
|
+
tool.description,
|
|
179
|
+
tool.parameters,
|
|
180
|
+
(request) => broker.handleToolCall({
|
|
181
|
+
sessionId,
|
|
182
|
+
turnId: request.turnId,
|
|
183
|
+
toolCallId: request.toolCallId,
|
|
184
|
+
toolName: tool.name,
|
|
185
|
+
args: request.args,
|
|
186
|
+
}),
|
|
187
|
+
);
|
|
188
|
+
registeredNames.push(tool.internalName);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
await input.session.setAllowedTools(
|
|
192
|
+
registeredNames.length > 0
|
|
193
|
+
? registeredNames
|
|
194
|
+
: [noClientToolsSentinel(sessionId, requestId)],
|
|
195
|
+
);
|
|
196
|
+
} catch (error) {
|
|
197
|
+
broker.abortRequest({
|
|
198
|
+
sessionId,
|
|
199
|
+
requestId,
|
|
200
|
+
reason: 'Agent API SDK binding failed',
|
|
201
|
+
});
|
|
202
|
+
try {
|
|
203
|
+
await unregisterTools(input.session, registeredNames);
|
|
204
|
+
} catch {
|
|
205
|
+
// Preserve the binding error; cleanup was best-effort and all handlers are fail-closed.
|
|
206
|
+
}
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
let closed = false;
|
|
211
|
+
function ensureOpen() {
|
|
212
|
+
if (closed) {
|
|
213
|
+
throw runtimeError('AGENT_API_BINDING_CLOSED', 'Agent API SDK binding is closed');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return Object.freeze({
|
|
218
|
+
sessionId,
|
|
219
|
+
requestId,
|
|
220
|
+
nextToolCall() {
|
|
221
|
+
ensureOpen();
|
|
222
|
+
return broker.nextToolCall({ sessionId, requestId });
|
|
223
|
+
},
|
|
224
|
+
submitToolResult(result) {
|
|
225
|
+
ensureOpen();
|
|
226
|
+
return broker.submitToolResult({ sessionId, requestId, ...result });
|
|
227
|
+
},
|
|
228
|
+
async finish() {
|
|
229
|
+
ensureOpen();
|
|
230
|
+
broker.finishRequest({ sessionId, requestId });
|
|
231
|
+
closed = true;
|
|
232
|
+
await unregisterTools(input.session, registeredNames);
|
|
233
|
+
},
|
|
234
|
+
async abort(reason = 'Agent API request aborted') {
|
|
235
|
+
ensureOpen();
|
|
236
|
+
broker.abortRequest({ sessionId, requestId, reason });
|
|
237
|
+
closed = true;
|
|
238
|
+
await unregisterTools(input.session, registeredNames);
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return Object.freeze({ bindClientTools });
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export {
|
|
247
|
+
AgentApiRuntimeError,
|
|
248
|
+
CLIENT_TOOL_NAME_PATTERN,
|
|
249
|
+
NO_CLIENT_TOOLS_PREFIX,
|
|
250
|
+
createAgentApiRuntime,
|
|
251
|
+
normalizeClientToolDefinitions,
|
|
252
|
+
};
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_MAX_PENDING_TOOL_CALLS = 32;
|
|
4
|
+
|
|
5
|
+
class AgentApiToolBrokerError extends Error {
|
|
6
|
+
constructor(code, message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = 'AgentApiToolBrokerError';
|
|
9
|
+
this.code = code;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function brokerError(code, message) {
|
|
14
|
+
return new AgentApiToolBrokerError(code, message);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function requireId(value, label) {
|
|
18
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
19
|
+
throw brokerError('AGENT_API_INVALID_SCOPE', `${label} must be a non-empty string`);
|
|
20
|
+
}
|
|
21
|
+
return value.trim();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function normalizeToolNames(value) {
|
|
25
|
+
if (!Array.isArray(value)) {
|
|
26
|
+
throw brokerError('AGENT_API_INVALID_TOOLS', 'toolNames must be an array');
|
|
27
|
+
}
|
|
28
|
+
const names = value.map((name) => requireId(name, 'tool name'));
|
|
29
|
+
if (new Set(names).size !== names.length) {
|
|
30
|
+
throw brokerError('AGENT_API_INVALID_TOOLS', 'toolNames must not contain duplicates');
|
|
31
|
+
}
|
|
32
|
+
return new Set(names);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function normalizeMaxPendingToolCalls(value) {
|
|
36
|
+
const normalized = value ?? DEFAULT_MAX_PENDING_TOOL_CALLS;
|
|
37
|
+
if (!Number.isSafeInteger(normalized) || normalized < 1) {
|
|
38
|
+
throw brokerError(
|
|
39
|
+
'AGENT_API_INVALID_LIMIT',
|
|
40
|
+
'maxPendingToolCalls must be a positive safe integer',
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
return normalized;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function normalizeToolResult(input) {
|
|
47
|
+
if (typeof input.output !== 'string') {
|
|
48
|
+
throw brokerError('AGENT_API_INVALID_TOOL_RESULT', 'tool result output must be a string');
|
|
49
|
+
}
|
|
50
|
+
if (input.isError !== undefined && typeof input.isError !== 'boolean') {
|
|
51
|
+
throw brokerError('AGENT_API_INVALID_TOOL_RESULT', 'tool result isError must be a boolean');
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
output: input.output,
|
|
55
|
+
isError: input.isError === true,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function cloneArgs(value) {
|
|
60
|
+
try {
|
|
61
|
+
return structuredClone(value);
|
|
62
|
+
} catch {
|
|
63
|
+
throw brokerError('AGENT_API_INVALID_TOOL_ARGS', 'tool arguments must be structured-cloneable');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function createDeferred() {
|
|
68
|
+
let resolve;
|
|
69
|
+
let reject;
|
|
70
|
+
const promise = new Promise((resolvePromise, rejectPromise) => {
|
|
71
|
+
resolve = resolvePromise;
|
|
72
|
+
reject = rejectPromise;
|
|
73
|
+
});
|
|
74
|
+
return { promise, reject, resolve };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function createAgentApiToolBroker(options = {}) {
|
|
78
|
+
const maxPendingToolCalls = normalizeMaxPendingToolCalls(options.maxPendingToolCalls);
|
|
79
|
+
const activeRequests = new Map();
|
|
80
|
+
|
|
81
|
+
function requestForScope(input) {
|
|
82
|
+
const sessionId = requireId(input.sessionId, 'sessionId');
|
|
83
|
+
const requestId = requireId(input.requestId, 'requestId');
|
|
84
|
+
const request = activeRequests.get(sessionId);
|
|
85
|
+
if (request === undefined) {
|
|
86
|
+
throw brokerError('AGENT_API_REQUEST_NOT_ACTIVE', 'no active Agent API request for session');
|
|
87
|
+
}
|
|
88
|
+
if (request.requestId !== requestId) {
|
|
89
|
+
throw brokerError(
|
|
90
|
+
'AGENT_API_TOOL_RESULT_SCOPE_MISMATCH',
|
|
91
|
+
'Agent API request does not match the active session request',
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
return request;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function pendingToolCallCount() {
|
|
98
|
+
let count = 0;
|
|
99
|
+
for (const request of activeRequests.values()) count += request.pending.size;
|
|
100
|
+
return count;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function deliverEvent(request, event) {
|
|
104
|
+
const waiter = request.eventWaiters.shift();
|
|
105
|
+
if (waiter !== undefined) {
|
|
106
|
+
waiter.resolve(event);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
request.events.push(event);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function beginRequest(input) {
|
|
113
|
+
const sessionId = requireId(input.sessionId, 'sessionId');
|
|
114
|
+
const requestId = requireId(input.requestId, 'requestId');
|
|
115
|
+
if (activeRequests.has(sessionId)) {
|
|
116
|
+
throw brokerError(
|
|
117
|
+
'AGENT_API_SESSION_BUSY',
|
|
118
|
+
'session already has an active Agent API request',
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
const request = {
|
|
122
|
+
sessionId,
|
|
123
|
+
requestId,
|
|
124
|
+
toolNames: normalizeToolNames(input.toolNames),
|
|
125
|
+
seenToolCallIds: new Set(),
|
|
126
|
+
pending: new Map(),
|
|
127
|
+
events: [],
|
|
128
|
+
eventWaiters: [],
|
|
129
|
+
};
|
|
130
|
+
activeRequests.set(sessionId, request);
|
|
131
|
+
return { sessionId, requestId };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function handleToolCall(input) {
|
|
135
|
+
const sessionId = requireId(input.sessionId, 'sessionId');
|
|
136
|
+
const toolCallId = requireId(input.toolCallId, 'toolCallId');
|
|
137
|
+
const toolName = requireId(input.toolName, 'toolName');
|
|
138
|
+
const request = activeRequests.get(sessionId);
|
|
139
|
+
if (request === undefined) {
|
|
140
|
+
return Promise.reject(brokerError(
|
|
141
|
+
'AGENT_API_REQUEST_NOT_ACTIVE',
|
|
142
|
+
'no active Agent API request for SDK tool call',
|
|
143
|
+
));
|
|
144
|
+
}
|
|
145
|
+
if (!request.toolNames.has(toolName)) {
|
|
146
|
+
return Promise.reject(brokerError(
|
|
147
|
+
'AGENT_API_TOOL_NOT_DECLARED',
|
|
148
|
+
`tool "${toolName}" was not declared by the API client`,
|
|
149
|
+
));
|
|
150
|
+
}
|
|
151
|
+
if (request.seenToolCallIds.has(toolCallId)) {
|
|
152
|
+
return Promise.reject(brokerError(
|
|
153
|
+
'AGENT_API_TOOL_CALL_DUPLICATE',
|
|
154
|
+
`tool call "${toolCallId}" has already been accepted`,
|
|
155
|
+
));
|
|
156
|
+
}
|
|
157
|
+
if (pendingToolCallCount() >= maxPendingToolCalls) {
|
|
158
|
+
return Promise.reject(brokerError(
|
|
159
|
+
'AGENT_API_TOOL_CALL_LIMIT',
|
|
160
|
+
'too many client tool calls are waiting for results',
|
|
161
|
+
));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const deferred = createDeferred();
|
|
165
|
+
request.seenToolCallIds.add(toolCallId);
|
|
166
|
+
request.pending.set(toolCallId, deferred);
|
|
167
|
+
deliverEvent(request, Object.freeze({
|
|
168
|
+
type: 'client_tool_call',
|
|
169
|
+
sessionId,
|
|
170
|
+
requestId: request.requestId,
|
|
171
|
+
turnId: input.turnId,
|
|
172
|
+
toolCallId,
|
|
173
|
+
toolName,
|
|
174
|
+
args: cloneArgs(input.args),
|
|
175
|
+
}));
|
|
176
|
+
return deferred.promise;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function nextToolCall(input) {
|
|
180
|
+
const request = requestForScope(input);
|
|
181
|
+
const event = request.events.shift();
|
|
182
|
+
if (event !== undefined) return Promise.resolve(event);
|
|
183
|
+
const deferred = createDeferred();
|
|
184
|
+
request.eventWaiters.push(deferred);
|
|
185
|
+
return deferred.promise;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function submitToolResult(input) {
|
|
189
|
+
const request = requestForScope(input);
|
|
190
|
+
const toolCallId = requireId(input.toolCallId, 'toolCallId');
|
|
191
|
+
const pending = request.pending.get(toolCallId);
|
|
192
|
+
if (pending === undefined) {
|
|
193
|
+
throw brokerError(
|
|
194
|
+
'AGENT_API_TOOL_CALL_NOT_PENDING',
|
|
195
|
+
`tool call "${toolCallId}" is not waiting for a result`,
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
const result = normalizeToolResult(input);
|
|
199
|
+
request.pending.delete(toolCallId);
|
|
200
|
+
pending.resolve(result);
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function abortRequest(input) {
|
|
205
|
+
const request = requestForScope(input);
|
|
206
|
+
const reason = typeof input.reason === 'string' && input.reason.trim().length > 0
|
|
207
|
+
? input.reason.trim()
|
|
208
|
+
: 'request aborted';
|
|
209
|
+
const error = brokerError('AGENT_API_REQUEST_ABORTED', reason);
|
|
210
|
+
activeRequests.delete(request.sessionId);
|
|
211
|
+
request.events.length = 0;
|
|
212
|
+
for (const waiter of request.eventWaiters.splice(0)) waiter.reject(error);
|
|
213
|
+
for (const pending of request.pending.values()) pending.reject(error);
|
|
214
|
+
request.pending.clear();
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function finishRequest(input) {
|
|
219
|
+
const request = requestForScope(input);
|
|
220
|
+
if (request.pending.size > 0) {
|
|
221
|
+
throw brokerError(
|
|
222
|
+
'AGENT_API_REQUEST_HAS_PENDING_TOOLS',
|
|
223
|
+
'cannot finish a request while client tool results are pending',
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
const error = brokerError('AGENT_API_REQUEST_FINISHED', 'Agent API request finished');
|
|
227
|
+
activeRequests.delete(request.sessionId);
|
|
228
|
+
request.events.length = 0;
|
|
229
|
+
for (const waiter of request.eventWaiters.splice(0)) waiter.reject(error);
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return Object.freeze({
|
|
234
|
+
abortRequest,
|
|
235
|
+
beginRequest,
|
|
236
|
+
finishRequest,
|
|
237
|
+
handleToolCall,
|
|
238
|
+
nextToolCall,
|
|
239
|
+
pendingToolCallCount,
|
|
240
|
+
submitToolResult,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
module.exports = {
|
|
245
|
+
AgentApiToolBrokerError,
|
|
246
|
+
DEFAULT_MAX_PENDING_TOOL_CALLS,
|
|
247
|
+
createAgentApiToolBroker,
|
|
248
|
+
};
|
package/bin/profile-runtime.cjs
CHANGED
|
@@ -28,6 +28,8 @@ const LEGACY_PROFILE_ENTRIES = Object.freeze([
|
|
|
28
28
|
const MIGRATION_MARKER = '.legacy-profile-migrated-v1';
|
|
29
29
|
const SESSION_PATH_MIGRATION_MARKER = '.legacy-profile-session-paths-v2';
|
|
30
30
|
const SESSION_PATH_BACKUP_DIR = '.legacy-profile-session-paths-v2-backup';
|
|
31
|
+
const PERSONA_LANGUAGE_MIGRATION_MARKER = '.legacy-persona-language-v1';
|
|
32
|
+
const PERSONA_LANGUAGE_BACKUP = '.legacy-persona-language-v1-backup.json';
|
|
31
33
|
|
|
32
34
|
function normalizeProfileName(value) {
|
|
33
35
|
const normalized = String(value || '').trim().toLowerCase();
|
|
@@ -134,6 +136,56 @@ function backupFile(source, target, fsImpl) {
|
|
|
134
136
|
fsImpl.copyFileSync(source, target);
|
|
135
137
|
}
|
|
136
138
|
|
|
139
|
+
function readJsonObject(target, fsImpl) {
|
|
140
|
+
if (!fsImpl.existsSync(target)) return null;
|
|
141
|
+
try {
|
|
142
|
+
const text = fsImpl.readFileSync(target, 'utf8');
|
|
143
|
+
const parsed = JSON.parse(text.charCodeAt(0) === 0xFEFF ? text.slice(1) : text);
|
|
144
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : null;
|
|
145
|
+
} catch {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function writeMarkerOnce(target, text, fsImpl) {
|
|
151
|
+
try {
|
|
152
|
+
fsImpl.writeFileSync(target, text, { encoding: 'utf8', flag: 'wx' });
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if (error?.code !== 'EEXIST') throw error;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function repairDefaultProfilePersonaLanguage(sharedHome, fsImpl = fs) {
|
|
159
|
+
const paths = resolveProfilePaths(sharedHome, DEFAULT_PROFILE);
|
|
160
|
+
const marker = path.join(paths.home, PERSONA_LANGUAGE_MIGRATION_MARKER);
|
|
161
|
+
const profilePersonaPath = path.join(paths.home, 'persona.json');
|
|
162
|
+
const legacyPersonaPath = path.join(sharedHome, 'persona.json');
|
|
163
|
+
if (fsImpl.existsSync(marker) || !fsImpl.existsSync(profilePersonaPath)) return paths;
|
|
164
|
+
|
|
165
|
+
const profilePersona = readJsonObject(profilePersonaPath, fsImpl);
|
|
166
|
+
const legacyPersona = readJsonObject(legacyPersonaPath, fsImpl);
|
|
167
|
+
if (profilePersona === null || legacyPersona === null) return paths;
|
|
168
|
+
|
|
169
|
+
if (!Object.hasOwn(profilePersona, 'language')) {
|
|
170
|
+
const legacyLanguage = typeof legacyPersona.language === 'string'
|
|
171
|
+
? legacyPersona.language.trim()
|
|
172
|
+
: '';
|
|
173
|
+
if (legacyLanguage) {
|
|
174
|
+
const original = fsImpl.readFileSync(profilePersonaPath, 'utf8');
|
|
175
|
+
backupFile(profilePersonaPath, path.join(paths.home, PERSONA_LANGUAGE_BACKUP), fsImpl);
|
|
176
|
+
replaceTextFileIfUnchanged(
|
|
177
|
+
profilePersonaPath,
|
|
178
|
+
original,
|
|
179
|
+
`${JSON.stringify({ ...profilePersona, language: legacyLanguage }, null, 2)}\n`,
|
|
180
|
+
fsImpl,
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
writeMarkerOnce(marker, 'legacy persona language repaired once\n', fsImpl);
|
|
186
|
+
return paths;
|
|
187
|
+
}
|
|
188
|
+
|
|
137
189
|
function rewriteSessionState(statePath, legacySessionDir, profileSessionDir, backupRoot, relativeSessionDir, fsImpl) {
|
|
138
190
|
if (!fsImpl.existsSync(statePath)) return false;
|
|
139
191
|
const original = fsImpl.readFileSync(statePath, 'utf8');
|
|
@@ -251,6 +303,7 @@ function seedDefaultProfileFromLegacy(sharedHome, fsImpl = fs) {
|
|
|
251
303
|
if (error?.code !== 'EEXIST') throw error;
|
|
252
304
|
}
|
|
253
305
|
}
|
|
306
|
+
repairDefaultProfilePersonaLanguage(sharedHome, fsImpl);
|
|
254
307
|
return repairDefaultProfileSessionPaths(sharedHome, fsImpl);
|
|
255
308
|
}
|
|
256
309
|
|
|
@@ -258,6 +311,7 @@ module.exports = {
|
|
|
258
311
|
DEFAULT_PROFILE,
|
|
259
312
|
normalizeProfileName,
|
|
260
313
|
parseProfileLaunchArgs,
|
|
314
|
+
repairDefaultProfilePersonaLanguage,
|
|
261
315
|
repairDefaultProfileSessionPaths,
|
|
262
316
|
resolveProfilePaths,
|
|
263
317
|
seedDefaultProfileFromLegacy,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function replayWindowStartIndex(records, activeTurnCount, startsTurn) {
|
|
4
|
+
if (
|
|
5
|
+
!Array.isArray(records)
|
|
6
|
+
|| !Number.isSafeInteger(activeTurnCount)
|
|
7
|
+
|| activeTurnCount <= 0
|
|
8
|
+
|| typeof startsTurn !== 'function'
|
|
9
|
+
) {
|
|
10
|
+
return 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let remainingTurns = activeTurnCount;
|
|
14
|
+
for (let index = records.length - 1; index >= 0; index -= 1) {
|
|
15
|
+
if (!startsTurn(records[index])) continue;
|
|
16
|
+
remainingTurns -= 1;
|
|
17
|
+
if (remainingTurns === 0) return index;
|
|
18
|
+
}
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = { replayWindowStartIndex };
|
|
@@ -41,6 +41,7 @@ class SessionScrollbackArchive {
|
|
|
41
41
|
this.loadedChunks = new Map();
|
|
42
42
|
this.lineCount = 0;
|
|
43
43
|
this.loadedExisting = false;
|
|
44
|
+
this.activeTurnCount = undefined;
|
|
44
45
|
|
|
45
46
|
if (reset) {
|
|
46
47
|
this.reset();
|
|
@@ -108,6 +109,21 @@ class SessionScrollbackArchive {
|
|
|
108
109
|
return output;
|
|
109
110
|
}
|
|
110
111
|
|
|
112
|
+
setActiveTurnCount(count) {
|
|
113
|
+
if (!isNonNegativeInteger(count)) return false;
|
|
114
|
+
if (this.activeTurnCount === count) return true;
|
|
115
|
+
const previous = this.activeTurnCount;
|
|
116
|
+
this.activeTurnCount = count;
|
|
117
|
+
try {
|
|
118
|
+
fs.mkdirSync(this.directory, { recursive: true });
|
|
119
|
+
this.writeIndex(this.chunks, this.lineCount);
|
|
120
|
+
return true;
|
|
121
|
+
} catch {
|
|
122
|
+
this.activeTurnCount = previous;
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
111
127
|
reset() {
|
|
112
128
|
try {
|
|
113
129
|
fs.rmSync(this.directory, { recursive: true, force: true });
|
|
@@ -116,6 +132,7 @@ class SessionScrollbackArchive {
|
|
|
116
132
|
this.loadedChunks.clear();
|
|
117
133
|
this.lineCount = 0;
|
|
118
134
|
this.loadedExisting = false;
|
|
135
|
+
this.activeTurnCount = undefined;
|
|
119
136
|
}
|
|
120
137
|
|
|
121
138
|
clear() {
|
|
@@ -165,6 +182,9 @@ class SessionScrollbackArchive {
|
|
|
165
182
|
|
|
166
183
|
this.chunks = chunks;
|
|
167
184
|
this.lineCount = parsed.totalLines;
|
|
185
|
+
this.activeTurnCount = isNonNegativeInteger(parsed.activeTurnCount)
|
|
186
|
+
? parsed.activeTurnCount
|
|
187
|
+
: undefined;
|
|
168
188
|
this.loadedExisting = true;
|
|
169
189
|
} catch {}
|
|
170
190
|
}
|
|
@@ -195,6 +215,9 @@ class SessionScrollbackArchive {
|
|
|
195
215
|
schemaVersion: ARCHIVE_SCHEMA_VERSION,
|
|
196
216
|
totalLines,
|
|
197
217
|
chunks,
|
|
218
|
+
...(isNonNegativeInteger(this.activeTurnCount)
|
|
219
|
+
? { activeTurnCount: this.activeTurnCount }
|
|
220
|
+
: {}),
|
|
198
221
|
}));
|
|
199
222
|
}
|
|
200
223
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function resolveSubagentRunMode({ allowBackground, requested }) {
|
|
4
|
+
if (allowBackground !== true) {
|
|
5
|
+
return {
|
|
6
|
+
runInBackground: false,
|
|
7
|
+
forcedForParentResponsiveness: false,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
runInBackground: true,
|
|
13
|
+
forcedForParentResponsiveness: requested !== true,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = {
|
|
18
|
+
resolveSubagentRunMode,
|
|
19
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function createAddressedChannelFocusStore(options = {}) {
|
|
4
|
+
const maxItems = Math.max(1, Number(options.maxItems) || 3);
|
|
5
|
+
const onChange = typeof options.onChange === 'function' ? options.onChange : () => {};
|
|
6
|
+
let sequence = 0;
|
|
7
|
+
let items = [];
|
|
8
|
+
|
|
9
|
+
function snapshot() {
|
|
10
|
+
return items.map((item) => ({ ...item }));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function publish() {
|
|
14
|
+
onChange(snapshot());
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
pin(input) {
|
|
19
|
+
const item = {
|
|
20
|
+
id: `channel-focus-${++sequence}`,
|
|
21
|
+
chatId: String(input.chatId),
|
|
22
|
+
origin: String(input.origin ?? ''),
|
|
23
|
+
text: String(input.text ?? '').trim(),
|
|
24
|
+
};
|
|
25
|
+
items = [...items, item].slice(-maxItems);
|
|
26
|
+
publish();
|
|
27
|
+
return item.id;
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
clearChat(chatId) {
|
|
31
|
+
const expected = String(chatId);
|
|
32
|
+
const next = items.filter((item) => item.chatId !== expected);
|
|
33
|
+
if (next.length === items.length) return false;
|
|
34
|
+
items = next;
|
|
35
|
+
publish();
|
|
36
|
+
return true;
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
snapshot,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = {
|
|
44
|
+
createAddressedChannelFocusStore,
|
|
45
|
+
};
|
package/blun.mjs
CHANGED
|
@@ -13,6 +13,7 @@ import compactionModelPolicy from "./bin/compaction-model-policy.cjs";
|
|
|
13
13
|
import agentResumeSnapshot from "./bin/agent-resume-snapshot.cjs";
|
|
14
14
|
import sessionResumeCheckpoint from "./bin/session-resume-checkpoint.cjs";
|
|
15
15
|
import sessionScrollbackArchive from "./bin/session-scrollback-archive.cjs";
|
|
16
|
+
import sessionReplayWindowPolicy from "./bin/session-replay-window-policy.cjs";
|
|
16
17
|
import crypto$1, { createHash, randomBytes, randomInt, randomUUID, timingSafeEqual } from "node:crypto";
|
|
17
18
|
import * as fs$16 from "node:fs";
|
|
18
19
|
import Kt, { accessSync, appendFileSync, chmodSync, closeSync, constants, copyFileSync, createReadStream, createWriteStream, existsSync, fsyncSync, linkSync, lstatSync, mkdirSync, openSync, promises, readFileSync, readSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
@@ -50,6 +51,7 @@ const { resolveCompactionModelAlias } = compactionModelPolicy;
|
|
|
50
51
|
const { createAgentResumeSnapshot, restoreAgentResumeSnapshot } = agentResumeSnapshot;
|
|
51
52
|
const { loadResumeCheckpoint, writeResumeCheckpoint } = sessionResumeCheckpoint;
|
|
52
53
|
const { SessionScrollbackArchive, sessionScrollbackArchiveDirectory } = sessionScrollbackArchive;
|
|
54
|
+
const { replayWindowStartIndex } = sessionReplayWindowPolicy;
|
|
53
55
|
import { EventEmitter as EventEmitter$1 } from "node:events";
|
|
54
56
|
import { StringDecoder } from "node:string_decoder";
|
|
55
57
|
import co from "node:assert";
|
|
@@ -28242,6 +28244,16 @@ function readPersona$1(env = process.env) {
|
|
|
28242
28244
|
const resolved = readProfilePersona(env);
|
|
28243
28245
|
return resolved.persona;
|
|
28244
28246
|
}
|
|
28247
|
+
function defaultAnswerLanguageSystemBlock() {
|
|
28248
|
+
return [
|
|
28249
|
+
"## Default answer language — HARD RULE",
|
|
28250
|
+
"",
|
|
28251
|
+
"English is the initial language for new or unconfigured accounts, profiles, and sessions.",
|
|
28252
|
+
"An explicit language saved in the account, profile, or current session overrides this default.",
|
|
28253
|
+
"Detect the language of the user's latest conversational message and answer in that language, including languages such as Bengali.",
|
|
28254
|
+
"Tool output does not change the conversational language. This rule overrides the generic # Language section when no explicit language is active."
|
|
28255
|
+
].join("\n");
|
|
28256
|
+
}
|
|
28245
28257
|
/**
|
|
28246
28258
|
* Build the system-prompt block that teaches the agent its persona name, so it
|
|
28247
28259
|
* warmly adopts the name the user gave it. Empty string when no name is set.
|
|
@@ -28408,6 +28420,7 @@ function buildTemplateVars(context, promptVars, tools) {
|
|
|
28408
28420
|
const now = context.now instanceof Date ? context.now.toISOString() : context.now ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
28409
28421
|
const roleBase = context.roleAdditional ?? promptVars["ROLE_ADDITIONAL"] ?? promptVars["roleAdditional"] ?? "";
|
|
28410
28422
|
const roleAdditional = [
|
|
28423
|
+
defaultAnswerLanguageSystemBlock(),
|
|
28411
28424
|
personaSystemBlock(),
|
|
28412
28425
|
soulSystemBlock(),
|
|
28413
28426
|
identitySystemBlock(),
|
|
@@ -252785,7 +252798,7 @@ var init_agent_background_disabled = __esmMin((() => {
|
|
|
252785
252798
|
//#region ../../packages/agent-core/src/tools/builtin/collaboration/agent-background-enabled.md?raw
|
|
252786
252799
|
var agent_background_enabled_default;
|
|
252787
252800
|
var init_agent_background_enabled = __esmMin((() => {
|
|
252788
|
-
agent_background_enabled_default = "
|
|
252801
|
+
agent_background_enabled_default = "Subagents run detached whenever task management is available, so the parent remains responsive while delegated work continues. Completion arrives automatically in a later turn. Do not poll, sleep, or block on TaskOutput. Continue with other work or respond to the user. Use TaskUpdate to steer the running subagent and TaskStop only when it must be cancelled. Never fabricate or predict its result.";
|
|
252789
252802
|
}));
|
|
252790
252803
|
//#endregion
|
|
252791
252804
|
//#region ../../packages/agent-core/src/tools/builtin/collaboration/agent.md?raw
|
|
@@ -252805,7 +252818,7 @@ function formatBackgroundAgentResult(taskId, handle, description, allowBackgroun
|
|
|
252805
252818
|
"",
|
|
252806
252819
|
`description: ${description}`,
|
|
252807
252820
|
"",
|
|
252808
|
-
allowBackground ?
|
|
252821
|
+
allowBackground ? "next_step: The subagent continues independently. Do not wait or poll; remain responsive to the user. Use TaskUpdate to steer it and TaskStop only if it must be cancelled. Its completion arrives automatically in a later turn." : "next_step: The completion arrives automatically in a later turn.",
|
|
252809
252822
|
`resume_hint: To continue or recover this same subagent later, call Agent(resume="${handle.agentId}", prompt="..."). The parameter is agent_id ("${handle.agentId}"), NOT task_id ("${taskId}") or source_id from a later <notification>. Recovery cases: a later <notification type="task.lost" | "task.failed" | "task.killed"> for this subagent — its conversation history is preserved across session restarts and resume will pick it up.`
|
|
252810
252823
|
].join("\n");
|
|
252811
252824
|
}
|
|
@@ -252844,7 +252857,7 @@ function buildSubagentDescriptions(subagents) {
|
|
|
252844
252857
|
return `${header}\n Tools: ${subagent.tools.join(", ")}`;
|
|
252845
252858
|
}).join("\n");
|
|
252846
252859
|
}
|
|
252847
|
-
var AgentToolInputSchema, BACKGROUND_AGENT_UNAVAILABLE, AgentTool, USER_INTERRUPTED_SUBAGENT_MESSAGE;
|
|
252860
|
+
var AgentToolInputSchema, BACKGROUND_AGENT_UNAVAILABLE, AgentTool, USER_INTERRUPTED_SUBAGENT_MESSAGE, resolveSubagentRunMode;
|
|
252848
252861
|
var init_agent$1 = __esmMin((() => {
|
|
252849
252862
|
init_zod$1();
|
|
252850
252863
|
init_tool_access();
|
|
@@ -252857,6 +252870,7 @@ var init_agent$1 = __esmMin((() => {
|
|
|
252857
252870
|
init_agent_background_disabled();
|
|
252858
252871
|
init_agent_background_enabled();
|
|
252859
252872
|
init_agent$2();
|
|
252873
|
+
({ resolveSubagentRunMode } = createRequire(import.meta.url)("./bin/subagent-parent-responsiveness.cjs"));
|
|
252860
252874
|
AgentToolInputSchema = preprocess((input) => {
|
|
252861
252875
|
if (typeof input !== "object" || input === null || Array.isArray(input)) return input;
|
|
252862
252876
|
const normalized = { ...input };
|
|
@@ -252870,7 +252884,7 @@ var init_agent$1 = __esmMin((() => {
|
|
|
252870
252884
|
description: string().describe("Short task description (3-5 words) for UI display"),
|
|
252871
252885
|
subagent_type: string().optional().describe("One of the available agent types (see \"Available agent types\" in this tool description). Defaults to \"coder\" when omitted."),
|
|
252872
252886
|
resume: string().optional().describe("Optional agent ID to resume instead of creating a new instance. When set, do not also pass subagent_type — the resumed agent keeps its own type, and supplying both is rejected."),
|
|
252873
|
-
run_in_background: boolean$1().optional().describe("
|
|
252887
|
+
run_in_background: boolean$1().optional().describe("Compatibility option. When task management is available, subagents always run detached so the parent remains responsive."),
|
|
252874
252888
|
timeout_minutes: number$1().int().min(0).max(10080).optional().describe("Wall-clock interval before the same agent is continued automatically. Defaults to 240 minutes. Set 0 to disable the interval for this run.")
|
|
252875
252889
|
}));
|
|
252876
252890
|
object({
|
|
@@ -252906,14 +252920,18 @@ var init_agent$1 = __esmMin((() => {
|
|
|
252906
252920
|
let profileName = args.subagent_type?.length ? args.subagent_type : "coder";
|
|
252907
252921
|
const resumeAgentId = args.resume?.trim();
|
|
252908
252922
|
if (resumeAgentId !== void 0 && resumeAgentId.length > 0) profileName = await this.subagentHost.getProfileName?.(resumeAgentId) ?? "subagent";
|
|
252923
|
+
const { runInBackground } = resolveSubagentRunMode({
|
|
252924
|
+
allowBackground: this.allowBackground,
|
|
252925
|
+
requested: args.run_in_background
|
|
252926
|
+
});
|
|
252909
252927
|
return {
|
|
252910
|
-
description: `${
|
|
252928
|
+
description: `${runInBackground ? "Launching background" : "Launching"} ${profileName} agent: ${args.description}`,
|
|
252911
252929
|
accesses: ToolAccesses.none(),
|
|
252912
252930
|
display: {
|
|
252913
252931
|
kind: "agent_call",
|
|
252914
252932
|
agent_name: profileName,
|
|
252915
252933
|
prompt: args.prompt,
|
|
252916
|
-
background:
|
|
252934
|
+
background: runInBackground
|
|
252917
252935
|
},
|
|
252918
252936
|
approvalRule: this.name,
|
|
252919
252937
|
matchesRule: (ruleArgs) => matchesGlobRuleSubject(ruleArgs, profileName),
|
|
@@ -252923,14 +252941,17 @@ var init_agent$1 = __esmMin((() => {
|
|
|
252923
252941
|
async execution(args, { toolCallId, signal }) {
|
|
252924
252942
|
try {
|
|
252925
252943
|
signal.throwIfAborted();
|
|
252926
|
-
const runInBackground =
|
|
252944
|
+
const { runInBackground } = resolveSubagentRunMode({
|
|
252945
|
+
allowBackground: this.allowBackground,
|
|
252946
|
+
requested: args.run_in_background
|
|
252947
|
+
});
|
|
252927
252948
|
const requestedProfileName = args.subagent_type?.length ? args.subagent_type : void 0;
|
|
252928
252949
|
const resumeAgentId = args.resume?.trim();
|
|
252929
252950
|
if (resumeAgentId !== void 0 && resumeAgentId.length > 0 && requestedProfileName !== void 0) return {
|
|
252930
252951
|
output: "Cannot set subagent_type when resuming an existing agent. Resume by agent id only.",
|
|
252931
252952
|
isError: true
|
|
252932
252953
|
};
|
|
252933
|
-
if (
|
|
252954
|
+
if (args.run_in_background === true && !this.allowBackground) return {
|
|
252934
252955
|
output: BACKGROUND_AGENT_UNAVAILABLE,
|
|
252935
252956
|
isError: true
|
|
252936
252957
|
};
|
|
@@ -265750,10 +265771,10 @@ var init_agent = __esmMin((() => {
|
|
|
265750
265771
|
return this.resolveEffectiveSystemPrompt(this.config.systemPrompt, this.runtimeSystemPromptAppend);
|
|
265751
265772
|
}
|
|
265752
265773
|
get fastConversationSystemPrompt() {
|
|
265753
|
-
return [personaSystemBlock(), soulSystemBlock(), identitySystemBlock(), naturalPresenceSystemBlock(), conductSystemBlock(), `## Fast conversation mode
|
|
265774
|
+
return [defaultAnswerLanguageSystemBlock(), personaSystemBlock(), soulSystemBlock(), identitySystemBlock(), naturalPresenceSystemBlock(), conductSystemBlock(), `## Fast conversation mode
|
|
265754
265775
|
|
|
265755
265776
|
- Answer the user's current conversational message directly and concisely.
|
|
265756
|
-
- Use the language of the user's latest message unless the persona specifies a language override.
|
|
265777
|
+
- Use the language of the user's latest conversational message unless the persona or current session specifies a language override.
|
|
265757
265778
|
- Do not claim to have inspected files, run commands, used tools, or checked current external state.
|
|
265758
265779
|
- If the message actually requires work or live information, say that plainly instead of inventing a result.`].filter((block) => block.length > 0).join("\n\n");
|
|
265759
265780
|
}
|
|
@@ -342504,7 +342525,7 @@ const DEFAULT_INLINE_SUGGEST_LANGUAGES = {
|
|
|
342504
342525
|
};
|
|
342505
342526
|
const DEFAULT_TUI_CONFIG = TuiConfigSchema.parse({
|
|
342506
342527
|
theme: "auto",
|
|
342507
|
-
uiLocale: "
|
|
342528
|
+
uiLocale: "en",
|
|
342508
342529
|
disablePasteBurst: false,
|
|
342509
342530
|
editorCommand: null,
|
|
342510
342531
|
notifications: DEFAULT_NOTIFICATIONS_CONFIG,
|
|
@@ -419349,6 +419370,7 @@ var { projectUnaddressedTelegramContext } = createRequire(import.meta.url)("./bi
|
|
|
419349
419370
|
var { enqueueTelegramUrgent, rewriteTelegramUrgentEnvelope, telegramUrgentMessage } = createRequire(import.meta.url)("./bin/telegram-urgent-policy.cjs");
|
|
419350
419371
|
var { createDirectFocusController, createDirectReplyTurnStop, enqueueTelegramDirect, readDirectFocusCheckpoint, rewriteTelegramDirectEnvelope, telegramDirectMessage, writeDirectFocusCheckpoint } = createRequire(import.meta.url)("./bin/telegram-direct-focus-policy.cjs");
|
|
419351
419372
|
var { enqueueTelegramAddressed } = createRequire(import.meta.url)("./bin/telegram-addressed-priority.cjs");
|
|
419373
|
+
var { createAddressedChannelFocusStore } = createRequire(import.meta.url)("./bin/telegram-addressed-focus.cjs");
|
|
419352
419374
|
var { removeQueuedReloadCommands, removeQueuedSlashCommands } = createRequire(import.meta.url)("./bin/reload-queue-policy.cjs");
|
|
419353
419375
|
const MAX_BUFFERED_CONTEXT_MESSAGES = 20;
|
|
419354
419376
|
const MAX_BUFFERED_CONTEXT_CHARS = 24e3;
|
|
@@ -501854,6 +501876,23 @@ var QueuePaneComponent = class extends Container {
|
|
|
501854
501876
|
return lines;
|
|
501855
501877
|
}
|
|
501856
501878
|
};
|
|
501879
|
+
var AddressedChannelFocusPaneComponent = class extends Container {
|
|
501880
|
+
items;
|
|
501881
|
+
constructor(items) {
|
|
501882
|
+
super();
|
|
501883
|
+
this.items = items;
|
|
501884
|
+
}
|
|
501885
|
+
render(width) {
|
|
501886
|
+
const bar = chalk.hex(ACCENT)(LEFT_BAR$1);
|
|
501887
|
+
return this.items.slice(-3).map((item) => {
|
|
501888
|
+
const origin = item.origin.trim().length > 0 ? `${item.origin.trim()} ` : "Telegram ";
|
|
501889
|
+
const body = item.text.replaceAll(/\s+/g, " ").trim();
|
|
501890
|
+
const prefix = `${bar} ${currentTheme.fg("primary", "!")} ${currentTheme.fg("textStrong", origin)}`;
|
|
501891
|
+
const available = Math.max(1, width - visibleWidth(prefix));
|
|
501892
|
+
return truncateToWidth(`${prefix}${truncateToWidth(body, available, ELLIPSIS$3)}`, width, ELLIPSIS$3);
|
|
501893
|
+
});
|
|
501894
|
+
}
|
|
501895
|
+
};
|
|
501857
501896
|
//#endregion
|
|
501858
501897
|
//#region src/tui/utils/refresh-providers.ts
|
|
501859
501898
|
init_src$3();
|
|
@@ -506116,9 +506155,15 @@ var ScrollbackBuffer = class {
|
|
|
506116
506155
|
get totalLines() {
|
|
506117
506156
|
return this.archive.totalLines + this.snapshotLines.length;
|
|
506118
506157
|
}
|
|
506158
|
+
get activeTurnCount() {
|
|
506159
|
+
return this.archive instanceof SessionScrollbackArchive ? this.archive.activeTurnCount : void 0;
|
|
506160
|
+
}
|
|
506119
506161
|
archiveLines(lines) {
|
|
506120
506162
|
return this.archive.append(lines);
|
|
506121
506163
|
}
|
|
506164
|
+
setActiveTurnCount(count) {
|
|
506165
|
+
return this.archive instanceof SessionScrollbackArchive ? this.archive.setActiveTurnCount(count) : false;
|
|
506166
|
+
}
|
|
506122
506167
|
usePersistentArchive(directory, options) {
|
|
506123
506168
|
this.releaseArchive();
|
|
506124
506169
|
const archive = new SessionScrollbackArchive({
|
|
@@ -506515,12 +506560,17 @@ var ScrollbackController = class {
|
|
|
506515
506560
|
reset: !resumeCheckpointRestored,
|
|
506516
506561
|
reuse: resumeCheckpointRestored
|
|
506517
506562
|
});
|
|
506518
|
-
|
|
506519
|
-
|
|
506563
|
+
const activeTurnCount = resumeCheckpointRestored && loadedExisting && buffer.totalLines > 0 ? buffer.activeTurnCount : void 0;
|
|
506564
|
+
this.suppressReplayArchiveWrites = resumeCheckpointRestored && loadedExisting && activeTurnCount === void 0;
|
|
506565
|
+
return activeTurnCount;
|
|
506520
506566
|
}
|
|
506521
506567
|
finishSessionReplay() {
|
|
506568
|
+
this.persistActiveTurnCount(groupTurns(this.state.transcriptEntries).length);
|
|
506522
506569
|
this.suppressReplayArchiveWrites = false;
|
|
506523
506570
|
}
|
|
506571
|
+
persistActiveTurnCount(count) {
|
|
506572
|
+
this.buffer?.setActiveTurnCount(count);
|
|
506573
|
+
}
|
|
506524
506574
|
archiveComponents(components) {
|
|
506525
506575
|
const buffer = this.buffer;
|
|
506526
506576
|
if (buffer === void 0 || components.length === 0) return components.length === 0;
|
|
@@ -509544,6 +509594,21 @@ function createReplayRenderContext() {
|
|
|
509544
509594
|
suppressNextPlanModeOffNotice: false
|
|
509545
509595
|
};
|
|
509546
509596
|
}
|
|
509597
|
+
function replayRecordStartsVisibleTurn(record) {
|
|
509598
|
+
if (record?.type !== "message" || record.message?.role !== "user") return false;
|
|
509599
|
+
const message = record.message;
|
|
509600
|
+
if (backgroundOrigin(message) !== void 0) return false;
|
|
509601
|
+
if (message.origin?.kind === "hook_result" || message.origin?.kind === "injection") return false;
|
|
509602
|
+
if (message.origin?.kind === "shell_command") return message.origin.phase === "input";
|
|
509603
|
+
if (message.origin?.kind === "cron_job" || message.origin?.kind === "cron_missed") return false;
|
|
509604
|
+
if (isGoalForkClearedSystemReminder(message)) return false;
|
|
509605
|
+
if (goalOutcomeReminderFromSystemMessage(message) !== null) return false;
|
|
509606
|
+
const skill = skillActivationFromOrigin(message.origin);
|
|
509607
|
+
if (skill !== void 0) return message.origin?.kind === "skill_activation" && message.origin.trigger === "user-slash";
|
|
509608
|
+
const pluginCommand = pluginCommandFromOrigin(message.origin);
|
|
509609
|
+
if (pluginCommand !== void 0) return message.origin?.kind === "plugin_command" && message.origin.trigger === "user-slash";
|
|
509610
|
+
return true;
|
|
509611
|
+
}
|
|
509547
509612
|
function replayEntry(context, kind, content, renderMode, extras = {}) {
|
|
509548
509613
|
return {
|
|
509549
509614
|
id: nextTranscriptId(),
|
|
@@ -509810,9 +509875,9 @@ var SessionReplayRenderer = class {
|
|
|
509810
509875
|
this.host.showError(uiText("replay.error.unavailable"));
|
|
509811
509876
|
return false;
|
|
509812
509877
|
}
|
|
509813
|
-
this.host.scrollbackController.prepareSessionReplay(main);
|
|
509878
|
+
const activeTurnCount = this.host.scrollbackController.prepareSessionReplay(main);
|
|
509814
509879
|
this.hydrateSnapshot(main);
|
|
509815
|
-
await this.renderRecords(main);
|
|
509880
|
+
await this.renderRecords(main, activeTurnCount);
|
|
509816
509881
|
this.applyTerminalBackgroundAgentStatuses(main);
|
|
509817
509882
|
this.host.mergeAllTurnSteps();
|
|
509818
509883
|
this.host.requestTranscriptRender();
|
|
@@ -509880,9 +509945,11 @@ var SessionReplayRenderer = class {
|
|
|
509880
509945
|
state.footer.setBackgroundCounts(countActiveBackgroundTasks(sessionEventHandler.backgroundTasks));
|
|
509881
509946
|
state.ui.requestRender();
|
|
509882
509947
|
}
|
|
509883
|
-
async renderRecords(agent) {
|
|
509948
|
+
async renderRecords(agent, activeTurnCount) {
|
|
509884
509949
|
const context = createReplayRenderContext();
|
|
509885
|
-
|
|
509950
|
+
const startIndex = replayWindowStartIndex(agent.replay, activeTurnCount, replayRecordStartsVisibleTurn);
|
|
509951
|
+
for (let recordIndex = startIndex; recordIndex < agent.replay.length; recordIndex++) {
|
|
509952
|
+
const record = agent.replay[recordIndex];
|
|
509886
509953
|
this.renderRecord(context, record);
|
|
509887
509954
|
if (shouldYieldSessionReplay(recordIndex + 1, agent.replay.length)) await yieldSessionReplayControl();
|
|
509888
509955
|
}
|
|
@@ -515175,6 +515242,7 @@ function createTUIState(options) {
|
|
|
515175
515242
|
ui.setSurfaceEnabled(initialAppState.appearance?.surface !== void 0);
|
|
515176
515243
|
const transcriptContainer = new GutterContainer(1, 1);
|
|
515177
515244
|
const activityContainer = new GutterContainer(1, 1);
|
|
515245
|
+
const channelFocusContainer = new GutterContainer(1, 1);
|
|
515178
515246
|
const todoPanelContainer = new GutterContainer(1, 1);
|
|
515179
515247
|
const todoPanel = new TodoPanelComponent();
|
|
515180
515248
|
const queueContainer = new GutterContainer(1, 1);
|
|
@@ -515192,6 +515260,7 @@ function createTUIState(options) {
|
|
|
515192
515260
|
terminal,
|
|
515193
515261
|
transcriptContainer,
|
|
515194
515262
|
activityContainer,
|
|
515263
|
+
channelFocusContainer,
|
|
515195
515264
|
todoPanelContainer,
|
|
515196
515265
|
todoPanel,
|
|
515197
515266
|
queueContainer,
|
|
@@ -516705,6 +516774,9 @@ var BlunTUI = class {
|
|
|
516705
516774
|
this.startupTranscriptNotice = startupInput.startupTranscriptNotice;
|
|
516706
516775
|
this.onStartupNoticeShown = startupInput.onStartupNoticeShown;
|
|
516707
516776
|
this.state = createTUIState(tuiOptions);
|
|
516777
|
+
this.addressedChannelFocusStore = createAddressedChannelFocusStore({
|
|
516778
|
+
onChange: () => this.updateAddressedChannelFocus()
|
|
516779
|
+
});
|
|
516708
516780
|
this.state.loopIndicator.setRefreshHandler(() => {
|
|
516709
516781
|
void this.refreshLoopState();
|
|
516710
516782
|
});
|
|
@@ -517375,6 +517447,7 @@ var BlunTUI = class {
|
|
|
517375
517447
|
ui.clear();
|
|
517376
517448
|
ui.addChild(this.state.transcriptContainer);
|
|
517377
517449
|
ui.addChild(this.state.activityContainer);
|
|
517450
|
+
ui.addChild(this.state.channelFocusContainer);
|
|
517378
517451
|
ui.addChild(this.state.todoPanelContainer);
|
|
517379
517452
|
ui.addChild(this.state.queueContainer);
|
|
517380
517453
|
ui.addChild(this.state.quotaWarningContainer);
|
|
@@ -517383,7 +517456,7 @@ var BlunTUI = class {
|
|
|
517383
517456
|
ui.addChild(this.state.editorContainer);
|
|
517384
517457
|
if (ui instanceof BottomPinnedTUI) {
|
|
517385
517458
|
ui.pinFromIndex = ui.children.indexOf(this.state.quotaWarningContainer);
|
|
517386
|
-
ui.chromeFromIndex = ui.children.indexOf(this.state.
|
|
517459
|
+
ui.chromeFromIndex = ui.children.indexOf(this.state.channelFocusContainer);
|
|
517387
517460
|
ui.overlayRowsProvider = () => this.state.editor.getAutocompleteRows();
|
|
517388
517461
|
for (const delay of [
|
|
517389
517462
|
0,
|
|
@@ -517595,7 +517668,8 @@ var BlunTUI = class {
|
|
|
517595
517668
|
outboxMarker: outboxMarker(),
|
|
517596
517669
|
transcriptStart: this.state.transcriptEntries.length,
|
|
517597
517670
|
contextOnly: false,
|
|
517598
|
-
directFocus: queued.channelDirect === true
|
|
517671
|
+
directFocus: queued.channelDirect === true,
|
|
517672
|
+
channelFocusId: queued.channelFocusId
|
|
517599
517673
|
}]);
|
|
517600
517674
|
this.pendingChannelReplyGuards.push(...installedGuards);
|
|
517601
517675
|
const inFlight = {
|
|
@@ -517649,12 +517723,13 @@ var BlunTUI = class {
|
|
|
517649
517723
|
}
|
|
517650
517724
|
return true;
|
|
517651
517725
|
}
|
|
517652
|
-
installChannelReplyGuard(chatId, contextOnly) {
|
|
517726
|
+
installChannelReplyGuard(chatId, contextOnly, channelFocusId) {
|
|
517653
517727
|
const guard = {
|
|
517654
517728
|
chatId,
|
|
517655
517729
|
outboxMarker: outboxMarker(),
|
|
517656
517730
|
transcriptStart: this.state.transcriptEntries.length,
|
|
517657
|
-
contextOnly
|
|
517731
|
+
contextOnly,
|
|
517732
|
+
channelFocusId
|
|
517658
517733
|
};
|
|
517659
517734
|
this.pendingChannelReplyGuards.push(guard);
|
|
517660
517735
|
return guard;
|
|
@@ -517663,6 +517738,18 @@ var BlunTUI = class {
|
|
|
517663
517738
|
const index = this.pendingChannelReplyGuards.indexOf(guard);
|
|
517664
517739
|
if (index >= 0) this.pendingChannelReplyGuards.splice(index, 1);
|
|
517665
517740
|
}
|
|
517741
|
+
pinAddressedChannelFocus(chatId, origin, text) {
|
|
517742
|
+
return this.addressedChannelFocusStore.pin({ chatId, origin, text });
|
|
517743
|
+
}
|
|
517744
|
+
clearAddressedChannelFocus(chatId) {
|
|
517745
|
+
return this.addressedChannelFocusStore.clearChat(chatId);
|
|
517746
|
+
}
|
|
517747
|
+
updateAddressedChannelFocus() {
|
|
517748
|
+
this.state.channelFocusContainer.clear();
|
|
517749
|
+
const items = this.addressedChannelFocusStore.snapshot();
|
|
517750
|
+
if (items.length > 0) this.state.channelFocusContainer.addChild(new AddressedChannelFocusPaneComponent(items));
|
|
517751
|
+
this.state.ui.requestRender();
|
|
517752
|
+
}
|
|
517666
517753
|
commitQueuedSteerAtStepStart(turnId) {
|
|
517667
517754
|
const inFlight = this.queueSteerInFlight;
|
|
517668
517755
|
if (inFlight === void 0 || inFlight.turnId !== String(turnId)) return;
|
|
@@ -517945,11 +518032,12 @@ var BlunTUI = class {
|
|
|
517945
518032
|
this.injectTelegramRemoteCommand(envelope, remoteCommand, acknowledge);
|
|
517946
518033
|
return;
|
|
517947
518034
|
}
|
|
518035
|
+
const channelFocusId = addressed && urgentEnvelope === void 0 && directEnvelope === void 0 ? this.pinAddressedChannelFocus(routedEnvelope.meta.chat_id, channelOrigin(routedEnvelope), envelope.text) : void 0;
|
|
517948
518036
|
injectChannelEnvelope({
|
|
517949
518037
|
canDeliver: () => this.session !== void 0 && this.state.appState.model.trim().length > 0,
|
|
517950
518038
|
isBusy: () => this.state.queuedMessages.length > 0 || this.queueSteerInFlight !== void 0 || this.deferUserMessages || this.streamingUI.hasActiveTurn() || this.state.appState.streamingPhase !== "idle" || this.state.appState.isCompacting,
|
|
517951
518039
|
deliverNow: (modelInput, displayText, origin, contextOnly, channelReportSources) => {
|
|
517952
|
-
this.sendChannelMessageInternal(this.requireSession(), modelInput, displayText, origin, routedEnvelope.meta.chat_id, routedEnvelope.meta["image_path"], contextOnly, false, acknowledge, false, void 0, directEnvelope !== void 0, directFocus.resumeGranted, channelReportSources);
|
|
518040
|
+
this.sendChannelMessageInternal(this.requireSession(), modelInput, displayText, origin, routedEnvelope.meta.chat_id, routedEnvelope.meta["image_path"], contextOnly, false, acknowledge, false, void 0, directEnvelope !== void 0, directFocus.resumeGranted, channelReportSources, channelFocusId);
|
|
517953
518041
|
},
|
|
517954
518042
|
enqueue: (modelInput, displayText, origin, contextOnly, channelReportSources) => {
|
|
517955
518043
|
const item = {
|
|
@@ -517962,6 +518050,7 @@ var BlunTUI = class {
|
|
|
517962
518050
|
channelReportSources: channelReportSources,
|
|
517963
518051
|
channelContextOnly: contextOnly,
|
|
517964
518052
|
channelAcknowledge: acknowledge,
|
|
518053
|
+
...channelFocusId === void 0 ? {} : { channelFocusId },
|
|
517965
518054
|
...urgentEnvelope !== void 0 ? { channelUrgent: true } : {},
|
|
517966
518055
|
...directEnvelope !== void 0 ? { channelDirect: true, channelDirectResume: directFocus.resumeGranted } : {},
|
|
517967
518056
|
...addressed && urgentEnvelope === void 0 && directEnvelope === void 0 ? { channelAddressed: true } : {},
|
|
@@ -518119,7 +518208,7 @@ var BlunTUI = class {
|
|
|
518119
518208
|
this.failSessionRequest(uiText("blunTui.session.sendFailed", { error: formatErrorMessage$2(error) }));
|
|
518120
518209
|
});
|
|
518121
518210
|
}
|
|
518122
|
-
sendChannelMessageInternal(session, modelInput, displayText, origin, channelChatId, channelImagePath, contextOnly = false, transcriptRendered = false, acknowledge, channelAttention = false, queueKey, channelDirect = false, channelDirectResume = false, channelReportSources = []) {
|
|
518211
|
+
sendChannelMessageInternal(session, modelInput, displayText, origin, channelChatId, channelImagePath, contextOnly = false, transcriptRendered = false, acknowledge, channelAttention = false, queueKey, channelDirect = false, channelDirectResume = false, channelReportSources = [], channelFocusId) {
|
|
518123
518212
|
armPersonalMemoryRememberIntent(session.id, displayText, {
|
|
518124
518213
|
permissionMode: this.state.appState.permissionMode,
|
|
518125
518214
|
channel: true
|
|
@@ -518139,7 +518228,8 @@ var BlunTUI = class {
|
|
|
518139
518228
|
outboxMarker: outboxMarker(),
|
|
518140
518229
|
transcriptStart: this.state.transcriptEntries.length,
|
|
518141
518230
|
contextOnly,
|
|
518142
|
-
directFocus: channelDirect
|
|
518231
|
+
directFocus: channelDirect,
|
|
518232
|
+
channelFocusId
|
|
518143
518233
|
};
|
|
518144
518234
|
if (installedGuard !== void 0) this.pendingChannelReplyGuard = installedGuard;
|
|
518145
518235
|
const imagePart = channelImagePath !== void 0 ? buildChannelImagePart(channelImagePath) : void 0;
|
|
@@ -518170,6 +518260,7 @@ var BlunTUI = class {
|
|
|
518170
518260
|
channelContextOnly: contextOnly,
|
|
518171
518261
|
channelTranscriptRendered: true,
|
|
518172
518262
|
channelAcknowledge: acknowledge,
|
|
518263
|
+
...channelFocusId === void 0 ? {} : { channelFocusId, channelAddressed: true },
|
|
518173
518264
|
...channelAttention === true ? { channelAttention: true } : {},
|
|
518174
518265
|
...channelDirect === true ? { channelDirect: true, channelDirectResume } : {},
|
|
518175
518266
|
...queueKey === void 0 ? {} : { queueKey },
|
|
@@ -518262,6 +518353,7 @@ var BlunTUI = class {
|
|
|
518262
518353
|
const args = entry.toolCallData?.args;
|
|
518263
518354
|
return String(args?.["chat_id"] ?? args?.["chatId"] ?? "") === guard.chatId;
|
|
518264
518355
|
}) || outboxGrewForChat(guard.outboxMarker, guard.chatId)) {
|
|
518356
|
+
this.clearAddressedChannelFocus?.(guard.chatId);
|
|
518265
518357
|
if (guard.directFocus === true) this.directFocusController.noteReplyDelivered(guard.chatId);
|
|
518266
518358
|
continue;
|
|
518267
518359
|
}
|
|
@@ -518287,6 +518379,7 @@ var BlunTUI = class {
|
|
|
518287
518379
|
if (finalText.length === 0) continue;
|
|
518288
518380
|
sendReplyFallback(guard.chatId, finalText, guard.contextOnly).then((sent) => {
|
|
518289
518381
|
if (!sent) return;
|
|
518382
|
+
this.clearAddressedChannelFocus?.(guard.chatId);
|
|
518290
518383
|
if (guard.directFocus === true) this.directFocusController.noteReplyDelivered(guard.chatId);
|
|
518291
518384
|
this.showStatus(uiText("blunTui.telegram.fallbackDelivered"));
|
|
518292
518385
|
});
|
|
@@ -518530,7 +518623,7 @@ var BlunTUI = class {
|
|
|
518530
518623
|
const activeSession = this.session ?? session;
|
|
518531
518624
|
if (item.mode === "channel") {
|
|
518532
518625
|
this.harness.withInteractiveAgent(item.agentId ?? "main", () => {
|
|
518533
|
-
this.sendChannelMessageInternal(activeSession, item.text, item.displayText ?? "", item.origin, item.channelChatId, item.channelImagePath, item.channelContextOnly, item.channelTranscriptRendered, item.channelAcknowledge, item.channelAttention, item.queueKey, item.channelDirect, item.channelDirectResume, item.channelReportSources);
|
|
518626
|
+
this.sendChannelMessageInternal(activeSession, item.text, item.displayText ?? "", item.origin, item.channelChatId, item.channelImagePath, item.channelContextOnly, item.channelTranscriptRendered, item.channelAcknowledge, item.channelAttention, item.queueKey, item.channelDirect, item.channelDirectResume, item.channelReportSources, item.channelFocusId);
|
|
518534
518627
|
});
|
|
518535
518628
|
return;
|
|
518536
518629
|
}
|
|
@@ -519134,9 +519227,11 @@ var BlunTUI = class {
|
|
|
519134
519227
|
markTranscriptComponent(component, entry);
|
|
519135
519228
|
this.state.transcriptContainer.addChild(component);
|
|
519136
519229
|
}
|
|
519137
|
-
const
|
|
519230
|
+
const turnBoundary = component !== null && this.isTurnBoundaryComponent(component);
|
|
519231
|
+
const trimmed = turnBoundary ? this.trimTranscriptWindow() : false;
|
|
519138
519232
|
const deferReplayWork = this.state.appState.isReplaying;
|
|
519139
519233
|
const merged = deferReplayWork ? false : this.mergeCurrentTurnSteps();
|
|
519234
|
+
if (turnBoundary && !deferReplayWork) this.scrollbackController.persistActiveTurnCount(groupTurns(this.state.transcriptEntries).length);
|
|
519140
519235
|
if ((component || trimmed || merged) && !deferReplayWork) this.state.ui.requestRender();
|
|
519141
519236
|
}
|
|
519142
519237
|
appendApprovalTranscriptEntry(request, response) {
|
|
@@ -520714,7 +520809,10 @@ function main() {
|
|
|
520714
520809
|
});
|
|
520715
520810
|
}).parse(process.argv);
|
|
520716
520811
|
}
|
|
520717
|
-
|
|
520812
|
+
function isDirectCliEntry(argvEntry = process.argv[1], moduleFilename = __filename) {
|
|
520813
|
+
return typeof argvEntry === "string" && argvEntry.length > 0 && path.resolve(argvEntry) === path.resolve(moduleFilename);
|
|
520814
|
+
}
|
|
520815
|
+
if (isDirectCliEntry()) main();
|
|
520718
520816
|
async function logStartupFailure(operation, error) {
|
|
520719
520817
|
log.error("startup failed", {
|
|
520720
520818
|
operation,
|
|
@@ -520725,4 +520823,4 @@ async function logStartupFailure(operation, error) {
|
|
|
520725
520823
|
} catch {}
|
|
520726
520824
|
}
|
|
520727
520825
|
//#endregion
|
|
520728
|
-
export { configureTelegramPluginLaunchMode, handleMainCommand, main };
|
|
520826
|
+
export { configureTelegramPluginLaunchMode, createBlunHarness, createBlunHostIdentity, handleMainCommand, isDirectCliEntry, main };
|