newmark-agent 0.4.6 → 0.4.8
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/assets/app-icon-dark.svg +6 -0
- package/dist/assets/app-icon-dark.svg +6 -0
- package/dist/cli-commands.js +2 -1
- package/dist/cli-discovery.js +2 -0
- package/dist/conversation-utility-host.bundle.cjs +577 -166
- package/dist/conversation-utility-host.js +3 -0
- package/dist/core/agent.d.ts +40 -4
- package/dist/core/agent.js +251 -49
- package/dist/core/agentKernelRunner.d.ts +3 -0
- package/dist/core/agentKernelRunner.js +74 -91
- package/dist/core/config.js +1 -1
- package/dist/core/conversationKernel.d.ts +40 -0
- package/dist/core/conversationKernel.js +219 -8
- package/dist/core/electronUtilityAgentClient.d.ts +8 -0
- package/dist/core/electronUtilityAgentClient.js +5 -1
- package/dist/core/electronUtilityRuntimePool.d.ts +15 -0
- package/dist/core/electronUtilityRuntimePool.js +11 -0
- package/dist/core/installUpdate.js +11 -8
- package/dist/core/mobilePairing.d.ts +1 -0
- package/dist/core/mobilePairing.js +15 -1
- package/dist/core/subagent.d.ts +10 -3
- package/dist/core/subagent.js +23 -8
- package/dist/core/toolPolicy.js +14 -3
- package/dist/core/utilityAgentProtocol.d.ts +29 -1
- package/dist/core/utilityHostToolRouter.js +18 -0
- package/dist/core/wslAgentClient.d.ts +8 -0
- package/dist/core/wslAgentClient.js +5 -1
- package/dist/core/wslAgentProtocol.d.ts +18 -1
- package/dist/core/wslAgentRuntimePool.d.ts +15 -0
- package/dist/core/wslAgentRuntimePool.js +11 -0
- package/dist/launcher.js +14 -11
- package/dist/main.js +207 -9
- package/dist/providers/chat-completions.adapter.js +6 -2
- package/dist/providers/responses.adapter.js +1 -0
- package/dist/server.d.ts +33 -1
- package/dist/server.js +696 -48
- package/dist/toolchain/registry-seeder.js +3 -1
- package/dist/tools/index.js +57 -6
- package/dist/tools/nativeTools.js +2 -1
- package/dist/ui/index.html +88 -101
- package/dist/wsl-agent-host.bundle.cjs +577 -166
- package/dist/wsl-agent-host.js +3 -0
- package/package.json +4 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BrowserControlRequest, BrowserControlResult } from './browserControl';
|
|
2
2
|
import { BrowserUseRequest } from './browserUse';
|
|
3
|
-
import { AgentPromptMessage, ConversationContextCompressOptions, ConversationKernelRunOptions, ConversationKernelRunResult, ConversationQueueMode, ConversationRuntimeState, ConversationStopResult } from './conversationKernel';
|
|
3
|
+
import { AgentPromptMessage, ConversationContextCompressOptions, ConversationKernelRunOptions, ConversationKernelRunResult, ConversationQueueAction, ConversationQueueMode, ConversationRuntimeState, ConversationStopResult } from './conversationKernel';
|
|
4
4
|
import { ConversationRuntimeTarget, NormalizedConversationTarget } from './conversationTarget';
|
|
5
5
|
import { AgentMode, AgentWorkEvent, ConversationInputEnvelope, GuideReceipt } from './types';
|
|
6
6
|
import type { AutoRouteRatingResult, ConversationSnapshot } from './agent';
|
|
@@ -40,6 +40,10 @@ export type UtilityHostToolRequest = (UtilityHostToolRequestBase & {
|
|
|
40
40
|
tool: 'browser_use';
|
|
41
41
|
args: BrowserUseRequest;
|
|
42
42
|
context: UtilityHostToolContext;
|
|
43
|
+
}) | (UtilityHostToolRequestBase & {
|
|
44
|
+
tool: 'screen_capture';
|
|
45
|
+
args: Record<string, unknown>;
|
|
46
|
+
context: UtilityHostToolContext;
|
|
43
47
|
}) | (UtilityHostToolRequestBase & {
|
|
44
48
|
tool: 'computer_use';
|
|
45
49
|
args: Record<string, unknown>;
|
|
@@ -96,6 +100,20 @@ export type UtilityAgentRequest = {
|
|
|
96
100
|
target: ConversationRuntimeTarget;
|
|
97
101
|
envelope: ConversationInputEnvelope;
|
|
98
102
|
};
|
|
103
|
+
} | {
|
|
104
|
+
id: string;
|
|
105
|
+
method: 'queue_action';
|
|
106
|
+
params: {
|
|
107
|
+
target: ConversationRuntimeTarget;
|
|
108
|
+
action: ConversationQueueAction;
|
|
109
|
+
input?: {
|
|
110
|
+
id?: string;
|
|
111
|
+
text?: string;
|
|
112
|
+
requestedMode?: string;
|
|
113
|
+
goalObjective?: string;
|
|
114
|
+
createdAt?: string;
|
|
115
|
+
};
|
|
116
|
+
};
|
|
99
117
|
} | {
|
|
100
118
|
id: string;
|
|
101
119
|
method: 'checkpoint';
|
|
@@ -210,6 +228,16 @@ export interface UtilityAgentSnapshotResult {
|
|
|
210
228
|
steering: string[];
|
|
211
229
|
followUp: string[];
|
|
212
230
|
};
|
|
231
|
+
queueItems?: Array<{
|
|
232
|
+
id: string;
|
|
233
|
+
text: string;
|
|
234
|
+
queueMode: 'steer' | 'followUp';
|
|
235
|
+
requestedMode?: string;
|
|
236
|
+
goalObjective?: string;
|
|
237
|
+
runId?: string;
|
|
238
|
+
createdAt: string;
|
|
239
|
+
}>;
|
|
240
|
+
queuePaused?: boolean;
|
|
213
241
|
workEvents: AgentWorkEvent[];
|
|
214
242
|
[key: string]: unknown;
|
|
215
243
|
}
|
|
@@ -126,6 +126,24 @@ function createUtilityHostToolHandler(options) {
|
|
|
126
126
|
throwIfAborted(signal);
|
|
127
127
|
return result;
|
|
128
128
|
}
|
|
129
|
+
if (request.tool === 'screen_capture') {
|
|
130
|
+
const args = request.args || {};
|
|
131
|
+
const target = String(args.target || '').toLowerCase() === 'application' ? 'application' : 'desktop';
|
|
132
|
+
const result = await (options.runComputer || computerUse_1.runComputerUse)({
|
|
133
|
+
action: target === 'application' ? 'app_observe' : 'observe',
|
|
134
|
+
appTarget: String(args.app_target || args.appTarget || ''),
|
|
135
|
+
windowHandle: target === 'application' ? String(args.app_target || args.appTarget || '') : '',
|
|
136
|
+
maxChars: Number(args.max_chars || args.maxChars || 30_000),
|
|
137
|
+
captureMaxWidth: Number(args.capture_max_width || args.captureMaxWidth),
|
|
138
|
+
captureMaxHeight: Number(args.capture_max_height || args.captureMaxHeight),
|
|
139
|
+
allowEphemeralVisionImage: request.context.allowEphemeralVisionImage === true,
|
|
140
|
+
workspacePath: request.target.workspacePath,
|
|
141
|
+
invocation: 'agent',
|
|
142
|
+
ownerId: `screen-capture:${request.target.runtimeKey}:${String(request.context.actorId || ROOT_AGENT_ACTOR_ID)}`,
|
|
143
|
+
});
|
|
144
|
+
throwIfAborted(signal);
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
129
147
|
const args = request.args || {};
|
|
130
148
|
const action = String(args.action || '').trim().toLowerCase();
|
|
131
149
|
const trustedComputerUseContext = request.context;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AgentMode, AgentWorkEvent, ConversationInputEnvelope, GuideReceipt } from './types';
|
|
2
|
+
import { ConversationQueueAction } from './conversationKernel';
|
|
2
3
|
import { TerminalTakeoverEvent, TerminalTakeoverOwnerFilter, TerminalTakeoverState } from '../tools/terminalTakeover';
|
|
3
4
|
import { WslAgentPromptRequest, WslAgentPromptResult, WslAutoRouteRatingResult, WslAgentWorkspace, WslAgentStopResult, WslConversationRewindResult, WslHostToolRequest } from './wslAgentProtocol';
|
|
4
5
|
import { ConversationRuntimeTarget, NormalizedConversationTarget } from './conversationTarget';
|
|
@@ -71,6 +72,13 @@ export declare class WslAgentClient {
|
|
|
71
72
|
snapshotTarget(target: ConversationRuntimeTarget): Promise<Record<string, unknown>>;
|
|
72
73
|
rewind(target: ConversationRuntimeTarget, messageIndex: number): Promise<WslConversationRewindResult>;
|
|
73
74
|
enqueueGuide(target: ConversationRuntimeTarget, envelope: ConversationInputEnvelope): Promise<GuideReceipt>;
|
|
75
|
+
queueAction(target: ConversationRuntimeTarget, action: ConversationQueueAction, input?: {
|
|
76
|
+
id?: string;
|
|
77
|
+
text?: string;
|
|
78
|
+
requestedMode?: string;
|
|
79
|
+
goalObjective?: string;
|
|
80
|
+
createdAt?: string;
|
|
81
|
+
}): Promise<Record<string, unknown>>;
|
|
74
82
|
checkpoint(target: ConversationRuntimeTarget): Promise<Record<string, unknown>>;
|
|
75
83
|
contextCompress(target: ConversationRuntimeTarget, options?: {
|
|
76
84
|
keepRecent?: number;
|
|
@@ -313,6 +313,10 @@ class WslAgentClient {
|
|
|
313
313
|
await this.start();
|
|
314
314
|
return await this.request('guide', { target: await this.mapTarget(target), envelope }, 5_000);
|
|
315
315
|
}
|
|
316
|
+
async queueAction(target, action, input = {}) {
|
|
317
|
+
await this.start();
|
|
318
|
+
return await this.request('queue_action', { target: await this.mapTarget(target), action, input }, 5_000);
|
|
319
|
+
}
|
|
316
320
|
async checkpoint(target) {
|
|
317
321
|
await this.start();
|
|
318
322
|
return await this.request('checkpoint', { target: await this.mapTarget(target) }, 5_000);
|
|
@@ -536,7 +540,7 @@ class WslAgentClient {
|
|
|
536
540
|
else if (!this.hostToolHandler) {
|
|
537
541
|
result = { requestId: request.requestId, ok: false, error: 'No Windows host tool handler is registered' };
|
|
538
542
|
}
|
|
539
|
-
else if (!['browser_control', 'computer_use', 'browser_use', 'automation', 'terminal_takeover'].includes(request.tool)) {
|
|
543
|
+
else if (!['browser_control', 'screen_capture', 'computer_use', 'browser_use', 'automation', 'terminal_takeover'].includes(request.tool)) {
|
|
540
544
|
result = { requestId: request.requestId, ok: false, error: `WSL host tool is not allowed: ${String(request.tool)}` };
|
|
541
545
|
}
|
|
542
546
|
else {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AgentMode, AgentWorkEvent, ConversationInputEnvelope, GuideReceipt } from './types';
|
|
2
|
-
import { AgentPromptMessage, ConversationContextCompressOptions, ConversationKernelRunOptions, ConversationKernelRunResult, ConversationQueueMode, ConversationStopResult } from './conversationKernel';
|
|
2
|
+
import { AgentPromptMessage, ConversationContextCompressOptions, ConversationKernelRunOptions, ConversationKernelRunResult, ConversationQueueAction, ConversationQueueMode, ConversationStopResult } from './conversationKernel';
|
|
3
3
|
import { ConversationRuntimeTarget } from './conversationTarget';
|
|
4
4
|
import { TerminalTakeoverEvent, TerminalTakeoverOwnerFilter, TerminalTakeoverState } from '../tools/terminalTakeover';
|
|
5
5
|
import { BrowserUseRequest } from './browserUse';
|
|
@@ -42,6 +42,9 @@ interface WslHostToolRequestBase {
|
|
|
42
42
|
export type WslHostToolRequest = (WslHostToolRequestBase & {
|
|
43
43
|
tool: 'browser_control';
|
|
44
44
|
args: BrowserControlRequest;
|
|
45
|
+
}) | (WslHostToolRequestBase & {
|
|
46
|
+
tool: 'screen_capture';
|
|
47
|
+
args: Record<string, unknown>;
|
|
45
48
|
}) | (WslHostToolRequestBase & {
|
|
46
49
|
tool: 'computer_use';
|
|
47
50
|
args: Record<string, unknown>;
|
|
@@ -108,6 +111,20 @@ export type WslAgentRequest = {
|
|
|
108
111
|
target: ConversationRuntimeTarget;
|
|
109
112
|
envelope: ConversationInputEnvelope;
|
|
110
113
|
};
|
|
114
|
+
} | {
|
|
115
|
+
id: string;
|
|
116
|
+
method: 'queue_action';
|
|
117
|
+
params: {
|
|
118
|
+
target: ConversationRuntimeTarget;
|
|
119
|
+
action: ConversationQueueAction;
|
|
120
|
+
input?: {
|
|
121
|
+
id?: string;
|
|
122
|
+
text?: string;
|
|
123
|
+
requestedMode?: string;
|
|
124
|
+
goalObjective?: string;
|
|
125
|
+
createdAt?: string;
|
|
126
|
+
};
|
|
127
|
+
};
|
|
111
128
|
} | {
|
|
112
129
|
id: string;
|
|
113
130
|
method: 'checkpoint';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AgentMode, AgentWorkEvent, ConversationInputEnvelope, GuideReceipt } from './types';
|
|
2
|
+
import { ConversationQueueAction } from './conversationKernel';
|
|
2
3
|
import { ConversationRuntimeTarget, NormalizedConversationTarget } from './conversationTarget';
|
|
3
4
|
import { WslHostToolHandler } from './wslAgentClient';
|
|
4
5
|
import { WslAgentPromptRequest, WslAgentPromptResult, WslAutoRouteRatingResult, WslAgentStopResult, WslConversationRewindResult } from './wslAgentProtocol';
|
|
@@ -10,6 +11,13 @@ export interface WslTargetRuntimeClient {
|
|
|
10
11
|
rewind(target: ConversationRuntimeTarget, messageIndex: number): Promise<WslConversationRewindResult>;
|
|
11
12
|
requestStop(target: ConversationRuntimeTarget, runId?: string): Promise<WslAgentStopResult>;
|
|
12
13
|
enqueueGuide(target: ConversationRuntimeTarget, envelope: ConversationInputEnvelope): Promise<GuideReceipt>;
|
|
14
|
+
queueAction?(target: ConversationRuntimeTarget, action: ConversationQueueAction, input?: {
|
|
15
|
+
id?: string;
|
|
16
|
+
text?: string;
|
|
17
|
+
requestedMode?: string;
|
|
18
|
+
goalObjective?: string;
|
|
19
|
+
createdAt?: string;
|
|
20
|
+
}): Promise<Record<string, unknown>>;
|
|
13
21
|
checkpoint(target: ConversationRuntimeTarget): Promise<Record<string, unknown>>;
|
|
14
22
|
contextCompress?(target: ConversationRuntimeTarget, options?: {
|
|
15
23
|
keepRecent?: number;
|
|
@@ -73,6 +81,13 @@ export declare class WslAgentRuntimePool {
|
|
|
73
81
|
rewind(target: ConversationRuntimeTarget, messageIndex: number): Promise<WslConversationRewindResult>;
|
|
74
82
|
requestStop(target: ConversationRuntimeTarget, runId?: string): Promise<WslPoolStopResult>;
|
|
75
83
|
enqueueGuide(envelope: ConversationInputEnvelope): Promise<GuideReceipt>;
|
|
84
|
+
queueAction(target: ConversationRuntimeTarget, action: ConversationQueueAction, input?: {
|
|
85
|
+
id?: string;
|
|
86
|
+
text?: string;
|
|
87
|
+
requestedMode?: string;
|
|
88
|
+
goalObjective?: string;
|
|
89
|
+
createdAt?: string;
|
|
90
|
+
}): Promise<Record<string, unknown>>;
|
|
76
91
|
checkpoint(target: ConversationRuntimeTarget): Promise<Record<string, unknown>>;
|
|
77
92
|
contextCompress(target: ConversationRuntimeTarget, options?: {
|
|
78
93
|
keepRecent?: number;
|
|
@@ -195,6 +195,17 @@ class WslAgentRuntimePool {
|
|
|
195
195
|
this.release(entry, true);
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
|
+
async queueAction(target, action, input = {}) {
|
|
199
|
+
const entry = await this.acquireExisting(target);
|
|
200
|
+
if (!entry || !entry.client.queueAction)
|
|
201
|
+
throw new Error('Target conversation is not running');
|
|
202
|
+
try {
|
|
203
|
+
return await entry.client.queueAction(entry.target, action, input);
|
|
204
|
+
}
|
|
205
|
+
finally {
|
|
206
|
+
this.release(entry, true);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
198
209
|
async checkpoint(target) {
|
|
199
210
|
const normalized = (0, conversationTarget_1.normalizeConversationTarget)(target);
|
|
200
211
|
const entry = await this.acquireExisting(normalized);
|
package/dist/launcher.js
CHANGED
|
@@ -312,6 +312,19 @@ if (isGui) {
|
|
|
312
312
|
launchGui();
|
|
313
313
|
}
|
|
314
314
|
else if (isTui) {
|
|
315
|
+
// 远程触及开关开启 → 后端托管启动 mobile server(不阻塞 TUI 其他功能;TUI 退出即随终端托管结束)
|
|
316
|
+
try {
|
|
317
|
+
const { ConfigManager } = require('./core/config');
|
|
318
|
+
const tuiConfig = new ConfigManager(root);
|
|
319
|
+
if (tuiConfig.getBool('remote', 'touch_enabled')) {
|
|
320
|
+
const { runServer } = require('./server');
|
|
321
|
+
runServer(root);
|
|
322
|
+
console.log('[Newmark] mobile server hosted (remote touch enabled)');
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
console.error('[Newmark] TUI hosted mobile server failed:', error instanceof Error ? error.message : String(error));
|
|
327
|
+
}
|
|
315
328
|
const { start } = require('./tui/src/app');
|
|
316
329
|
start({ root, workspacePath: resolveTuiWorkspacePath(args, root), desktopDist: __dirname });
|
|
317
330
|
}
|
|
@@ -363,18 +376,8 @@ else if (isCli || (!isServer && isTerminal())) {
|
|
|
363
376
|
runCli(root);
|
|
364
377
|
}
|
|
365
378
|
else {
|
|
366
|
-
// Server mode - start HTTP server
|
|
379
|
+
// Server mode - start HTTP server(不绑定启动浏览器)
|
|
367
380
|
const { runServer } = require('./server');
|
|
368
381
|
runServer(root);
|
|
369
|
-
if (!args.includes('--no-browser')) {
|
|
370
|
-
const { exec } = require('child_process');
|
|
371
|
-
const port = 47890;
|
|
372
|
-
const cmd = process.platform === 'win32'
|
|
373
|
-
? `start http://localhost:${port}`
|
|
374
|
-
: process.platform === 'darwin'
|
|
375
|
-
? `open http://localhost:${port}`
|
|
376
|
-
: `xdg-open http://localhost:${port}`;
|
|
377
|
-
exec(cmd);
|
|
378
|
-
}
|
|
379
382
|
}
|
|
380
383
|
//# sourceMappingURL=launcher.js.map
|
package/dist/main.js
CHANGED
|
@@ -120,6 +120,7 @@ let _forceQuit = false;
|
|
|
120
120
|
let forcedExitTimer = null;
|
|
121
121
|
let electronBrowserUseHost = null;
|
|
122
122
|
let browserUseEngine = null;
|
|
123
|
+
const mobileServerWorkEventSubscribers = new Set();
|
|
123
124
|
// A single renderer can host several hidden conversation-bound guests. The
|
|
124
125
|
// legacy host map is retained for focused-window discovery, while this map is
|
|
125
126
|
// the authoritative Browser-Use/right-sidebar binding.
|
|
@@ -288,7 +289,7 @@ async function resetWslAgentClient() {
|
|
|
288
289
|
if (wslAgentClient)
|
|
289
290
|
await wslAgentClient.resetAgent();
|
|
290
291
|
}
|
|
291
|
-
function broadcastAgentWorkEvent(event) {
|
|
292
|
+
function broadcastAgentWorkEvent(event, mirrorToMobile = true) {
|
|
292
293
|
const workEvent = event;
|
|
293
294
|
if ((workEvent.type === 'done' || workEvent.type === 'error') && workEvent.runtimeKey) {
|
|
294
295
|
browserUseEngine?.clearRuntime(workEvent.runtimeKey);
|
|
@@ -299,6 +300,14 @@ function broadcastAgentWorkEvent(event) {
|
|
|
299
300
|
continue;
|
|
300
301
|
win.webContents.send('agent:workEvent', event);
|
|
301
302
|
}
|
|
303
|
+
if (mirrorToMobile) {
|
|
304
|
+
for (const listener of mobileServerWorkEventSubscribers) {
|
|
305
|
+
try {
|
|
306
|
+
listener(event);
|
|
307
|
+
}
|
|
308
|
+
catch { /* ignore disconnected mobile bridge */ }
|
|
309
|
+
}
|
|
310
|
+
}
|
|
302
311
|
}
|
|
303
312
|
function ensureConversationKernel(root) {
|
|
304
313
|
if (!agent)
|
|
@@ -420,9 +429,10 @@ function relayFlowAgentWorkEvents(flowAgent, target) {
|
|
|
420
429
|
});
|
|
421
430
|
}
|
|
422
431
|
function themedAppIconPath() {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
432
|
+
// Fixed black-on-white icon across every theme: the titlebar, taskbar, tray,
|
|
433
|
+
// and Windows executable all share the same dark icon asset.
|
|
434
|
+
const compactPath = path.join(__dirname, 'assets', 'app-icon-dark-64.png');
|
|
435
|
+
return fs.existsSync(compactPath) ? compactPath : appAssetPath('app-icon-dark.png');
|
|
426
436
|
}
|
|
427
437
|
function createAppIconImage(size) {
|
|
428
438
|
const image = electron_1.nativeImage.createFromPath(themedAppIconPath());
|
|
@@ -1881,6 +1891,190 @@ else {
|
|
|
1881
1891
|
ensureWorkspaceRegistryWatcher();
|
|
1882
1892
|
restoreStoredFlowSuspension();
|
|
1883
1893
|
recordStartup('agent-ready');
|
|
1894
|
+
// 远程触及开关开启 → GUI 进程内托管启动 mobile server(托盘常驻不中断)
|
|
1895
|
+
if (agent.config.getBool('remote', 'touch_enabled')) {
|
|
1896
|
+
try {
|
|
1897
|
+
const { runServer } = require('./server');
|
|
1898
|
+
runServer(root, {
|
|
1899
|
+
agent,
|
|
1900
|
+
automation,
|
|
1901
|
+
onWorkEvent: event => broadcastAgentWorkEvent(event, false),
|
|
1902
|
+
subscribeWorkEvents: listener => {
|
|
1903
|
+
mobileServerWorkEventSubscribers.add(listener);
|
|
1904
|
+
return () => mobileServerWorkEventSubscribers.delete(listener);
|
|
1905
|
+
},
|
|
1906
|
+
conversationUiState: async (requested) => {
|
|
1907
|
+
const target = conversationRuntimeTarget(requested);
|
|
1908
|
+
const snapshot = wslBackendEnabled()
|
|
1909
|
+
? await ensureWslConversationPool().snapshot(target)
|
|
1910
|
+
: await ensureElectronUtilityPool().snapshot(target);
|
|
1911
|
+
const flowRunning = flowRunningForTarget(target);
|
|
1912
|
+
const flowSuspension = flowSuspensionForTarget(target);
|
|
1913
|
+
return {
|
|
1914
|
+
...snapshot,
|
|
1915
|
+
flow: flowRunning ? {
|
|
1916
|
+
running: true,
|
|
1917
|
+
paused: false,
|
|
1918
|
+
name: flowRunning.name,
|
|
1919
|
+
promptText: String(activeFlowStateFor(target)?.input || ''),
|
|
1920
|
+
message: '',
|
|
1921
|
+
} : flowSuspension ? {
|
|
1922
|
+
running: true,
|
|
1923
|
+
paused: true,
|
|
1924
|
+
name: flowSuspension.workflowName || '',
|
|
1925
|
+
promptText: String(flowSuspension.input || ''),
|
|
1926
|
+
message: String(flowSuspension.message || ''),
|
|
1927
|
+
reason: flowSuspension.reason || '',
|
|
1928
|
+
} : null,
|
|
1929
|
+
};
|
|
1930
|
+
},
|
|
1931
|
+
conversationUiAction: async (requested, action, value, input) => {
|
|
1932
|
+
const target = conversationRuntimeTarget(requested);
|
|
1933
|
+
if (action.startsWith('queue_')) {
|
|
1934
|
+
const queueAction = action === 'queue_enqueue' ? 'enqueue'
|
|
1935
|
+
: action === 'queue_update' ? 'update'
|
|
1936
|
+
: action === 'queue_delete' ? 'delete'
|
|
1937
|
+
: action === 'queue_toggle_pause' ? 'toggle_pause'
|
|
1938
|
+
: 'guide';
|
|
1939
|
+
const queueInput = {
|
|
1940
|
+
id: String(input?.id || ''),
|
|
1941
|
+
text: String(input?.text || value || ''),
|
|
1942
|
+
requestedMode: String(input?.requestedMode || 'build'),
|
|
1943
|
+
goalObjective: String(input?.goalObjective || ''),
|
|
1944
|
+
createdAt: String(input?.createdAt || ''),
|
|
1945
|
+
};
|
|
1946
|
+
return wslBackendEnabled()
|
|
1947
|
+
? await ensureWslConversationPool().queueAction(target, queueAction, queueInput)
|
|
1948
|
+
: await ensureElectronUtilityPool().queueAction(target, queueAction, queueInput);
|
|
1949
|
+
}
|
|
1950
|
+
if (action === 'goal_update') {
|
|
1951
|
+
return { goal: await mutateTargetConversation(target, () => {
|
|
1952
|
+
const isolated = isolatedConversationAgent(target);
|
|
1953
|
+
isolated.updateGoal(String(value || '').trim());
|
|
1954
|
+
isolated.setMode('goal');
|
|
1955
|
+
isolated.saveWorkspaceConversationState(true);
|
|
1956
|
+
return isolated.getConversationSnapshot(target.conversationId).goal;
|
|
1957
|
+
}) };
|
|
1958
|
+
}
|
|
1959
|
+
if (action === 'goal_guide' || action === 'conversation_guide') {
|
|
1960
|
+
const objective = action === 'goal_guide' ? String(value || '').trim() : '';
|
|
1961
|
+
const guideText = String(value || '').trim();
|
|
1962
|
+
const snapshot = wslBackendEnabled()
|
|
1963
|
+
? await ensureWslConversationPool().snapshot(target)
|
|
1964
|
+
: await ensureElectronUtilityPool().snapshot(target);
|
|
1965
|
+
const runtime = snapshot.runtime;
|
|
1966
|
+
if (!guideText || !runtime?.running || !runtime.runId) {
|
|
1967
|
+
return { ok: false, error: action === 'goal_guide'
|
|
1968
|
+
? 'There is no active Build for this Goal Guide.'
|
|
1969
|
+
: 'Target conversation is not running.' };
|
|
1970
|
+
}
|
|
1971
|
+
const prefix = 'Goal for the current Build:\n';
|
|
1972
|
+
const now = new Date().toISOString();
|
|
1973
|
+
const envelope = {
|
|
1974
|
+
clientMessageId: (0, crypto_1.randomUUID)(),
|
|
1975
|
+
guideId: (0, crypto_1.randomUUID)(),
|
|
1976
|
+
target: { workspaceId: target.workspaceId, conversationId: target.conversationId },
|
|
1977
|
+
runId: runtime.runId,
|
|
1978
|
+
deliveryMode: 'steer',
|
|
1979
|
+
text: objective ? prefix + objective : guideText,
|
|
1980
|
+
goalObjective: objective || undefined,
|
|
1981
|
+
createdAt: now,
|
|
1982
|
+
};
|
|
1983
|
+
const receipt = wslBackendEnabled()
|
|
1984
|
+
? await ensureWslConversationPool().enqueueGuide(envelope)
|
|
1985
|
+
: await ensureElectronUtilityPool().enqueueGuide(envelope);
|
|
1986
|
+
return { ok: receipt.status !== 'rejected', receipt };
|
|
1987
|
+
}
|
|
1988
|
+
if (action === 'goal_toggle_pause') {
|
|
1989
|
+
const resident = wslBackendEnabled()
|
|
1990
|
+
? await ensureWslConversationPool().toggleGoalPause(target)
|
|
1991
|
+
: await ensureElectronUtilityPool().toggleGoalPause(target);
|
|
1992
|
+
const paused = resident !== null ? resident : await mutateTargetConversation(target, () => isolatedConversationAgent(target).toggleGoalPause());
|
|
1993
|
+
return { ok: true, paused };
|
|
1994
|
+
}
|
|
1995
|
+
if (action === 'goal_clear') {
|
|
1996
|
+
const resident = wslBackendEnabled()
|
|
1997
|
+
? await ensureWslConversationPool().clearGoal(target)
|
|
1998
|
+
: await ensureElectronUtilityPool().clearGoal(target);
|
|
1999
|
+
if (resident === null)
|
|
2000
|
+
await mutateTargetConversation(target, () => isolatedConversationAgent(target).clearGoal());
|
|
2001
|
+
return { ok: true, cleared: true };
|
|
2002
|
+
}
|
|
2003
|
+
if (action === 'flow_pause')
|
|
2004
|
+
return await stopFlowForTarget(target);
|
|
2005
|
+
if (action === 'flow_resume')
|
|
2006
|
+
return await resumeFlowForTarget(String(value || ''), target);
|
|
2007
|
+
if (action === 'conversation_stop') {
|
|
2008
|
+
const snapshot = wslBackendEnabled()
|
|
2009
|
+
? await ensureWslConversationPool().snapshot(target)
|
|
2010
|
+
: await ensureElectronUtilityPool().snapshot(target);
|
|
2011
|
+
const runtime = snapshot.runtime;
|
|
2012
|
+
return wslBackendEnabled()
|
|
2013
|
+
? await ensureWslConversationPool().requestStop(target, runtime?.runId)
|
|
2014
|
+
: await ensureElectronUtilityPool().requestStop(target, runtime?.runId);
|
|
2015
|
+
}
|
|
2016
|
+
if (action === 'input_mode') {
|
|
2017
|
+
const mode = String(value || '') === 'next' ? 'next' : 'guide';
|
|
2018
|
+
const selected = wslBackendEnabled()
|
|
2019
|
+
? await ensureWslConversationPool().setInputMode(target, mode)
|
|
2020
|
+
: await ensureElectronUtilityPool().setInputMode(target, mode);
|
|
2021
|
+
return { ok: true, inputMode: selected || mode };
|
|
2022
|
+
}
|
|
2023
|
+
const flow = activeFlowStateFor(target);
|
|
2024
|
+
if (!flow?.abortController || !flow.flowAgent)
|
|
2025
|
+
return { ok: false, error: 'No active Flow accepts Guide input.' };
|
|
2026
|
+
const accepted = flow.flowAgent.queueActiveKernelMessage(String(value || '').trim(), 'steer') || false;
|
|
2027
|
+
return accepted ? { ok: true, accepted: true, flow: flow.name } : { ok: false, error: 'The current Flow Build is not accepting Guide input.' };
|
|
2028
|
+
},
|
|
2029
|
+
conversationPrompt: async (requested, message, requestedOptions) => {
|
|
2030
|
+
const target = conversationRuntimeTarget(requested);
|
|
2031
|
+
if (activeFlowStateFor(target))
|
|
2032
|
+
clearFlowSuspensionForNewWork(target);
|
|
2033
|
+
const snapshot = wslBackendEnabled()
|
|
2034
|
+
? await ensureWslConversationPool().snapshot(target)
|
|
2035
|
+
: await ensureElectronUtilityPool().snapshot(target);
|
|
2036
|
+
const requestedMode = String(requestedOptions?.requestedMode || '').toLowerCase();
|
|
2037
|
+
const goalObjective = String(requestedOptions?.goalObjective || '').trim();
|
|
2038
|
+
const mode = (goalObjective || requestedMode === 'goal') ? 'build' : String(snapshot.mode || 'build');
|
|
2039
|
+
const inputMode = String(requestedOptions?.inputMode || snapshot.inputMode || 'guide') === 'next' ? 'next' : 'guide';
|
|
2040
|
+
const options = {
|
|
2041
|
+
mode,
|
|
2042
|
+
model: String(snapshot.model || agent.ensureUsableModelSelection()),
|
|
2043
|
+
intelligence: String(snapshot.intelligence || agent.intelligence),
|
|
2044
|
+
inputMode,
|
|
2045
|
+
engine: agent.engine,
|
|
2046
|
+
};
|
|
2047
|
+
const queueMode = inputMode === 'guide' ? 'steer' : 'followUp';
|
|
2048
|
+
const promptMessage = goalObjective ? {
|
|
2049
|
+
text: message,
|
|
2050
|
+
visibleMode: 'goal',
|
|
2051
|
+
goalObjective,
|
|
2052
|
+
} : message;
|
|
2053
|
+
const result = wslBackendEnabled()
|
|
2054
|
+
? await ensureWslConversationPool().prompt({
|
|
2055
|
+
message: promptMessage,
|
|
2056
|
+
target,
|
|
2057
|
+
conversationId: target.conversationId,
|
|
2058
|
+
options,
|
|
2059
|
+
queueMode,
|
|
2060
|
+
workspace: target.workspace ? {
|
|
2061
|
+
id: target.workspace.id,
|
|
2062
|
+
name: target.workspace.name,
|
|
2063
|
+
path: target.workspace.path,
|
|
2064
|
+
isInternal: target.workspace.isInternal,
|
|
2065
|
+
kind: target.workspace.kind,
|
|
2066
|
+
} : null,
|
|
2067
|
+
})
|
|
2068
|
+
: await ensureElectronUtilityPool().prompt({ message: promptMessage, target, options, queueMode });
|
|
2069
|
+
return { ...result };
|
|
2070
|
+
},
|
|
2071
|
+
});
|
|
2072
|
+
recordStartup('mobile-server-hosted');
|
|
2073
|
+
}
|
|
2074
|
+
catch (error) {
|
|
2075
|
+
console.error('[Newmark] hosted mobile server failed:', error instanceof Error ? error.message : String(error));
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
1884
2078
|
}
|
|
1885
2079
|
};
|
|
1886
2080
|
const localConversationSnapshotForStartup = (target) => {
|
|
@@ -1964,6 +2158,8 @@ else {
|
|
|
1964
2158
|
return result.tokens.map(token => token.text).join('');
|
|
1965
2159
|
});
|
|
1966
2160
|
startupAgent.setAutomationManager(automation);
|
|
2161
|
+
const { setHostedServerAutomation } = require('./server');
|
|
2162
|
+
setHostedServerAutomation(automation);
|
|
1967
2163
|
automation.onChange(items => {
|
|
1968
2164
|
setTimeout(() => {
|
|
1969
2165
|
try {
|
|
@@ -2664,7 +2860,7 @@ else {
|
|
|
2664
2860
|
return await utilityHostToolHandler({ ...request, target: routedTarget, context: routedContext }, signal);
|
|
2665
2861
|
}
|
|
2666
2862
|
const result = await utilityHostToolHandler({ ...request, target: routedTarget, context: routedContext }, signal);
|
|
2667
|
-
return request.tool === 'computer_use' ? prepareWslComputerUseVisionResult(result) : result;
|
|
2863
|
+
return request.tool === 'computer_use' || request.tool === 'screen_capture' ? prepareWslComputerUseVisionResult(result) : result;
|
|
2668
2864
|
};
|
|
2669
2865
|
runWslHostTool.cancelTarget = (runtimeKey) => utilityHostToolHandler.cancelTarget(runtimeKey);
|
|
2670
2866
|
const ensureWslConversationPool = () => {
|
|
@@ -3024,7 +3220,7 @@ else {
|
|
|
3024
3220
|
}
|
|
3025
3221
|
}
|
|
3026
3222
|
});
|
|
3027
|
-
|
|
3223
|
+
const resumeFlowForTarget = async (response, targetInput) => {
|
|
3028
3224
|
if (!agent)
|
|
3029
3225
|
return { ok: false, error: 'No suspended Flow is waiting for user input.' };
|
|
3030
3226
|
const requestedTarget = targetInput ? conversationRuntimeTarget(targetInput) : null;
|
|
@@ -3158,7 +3354,8 @@ else {
|
|
|
3158
3354
|
await setTargetFlowMode(flowTarget, suspension.previousMode);
|
|
3159
3355
|
}
|
|
3160
3356
|
}
|
|
3161
|
-
}
|
|
3357
|
+
};
|
|
3358
|
+
electron_1.ipcMain.handle('flow:resume', async (_event, response, targetInput) => await resumeFlowForTarget(response, targetInput));
|
|
3162
3359
|
electron_1.ipcMain.handle('agent:setMode', async (_event, mode) => {
|
|
3163
3360
|
if (agent) {
|
|
3164
3361
|
const nextMode = mode;
|
|
@@ -3731,7 +3928,7 @@ else {
|
|
|
3731
3928
|
const accepted = state.flowAgent.queueActiveKernelMessage(text, 'steer') || false;
|
|
3732
3929
|
return accepted ? { ok: true, accepted: true, flow: state.name } : { ok: false, error: 'The current Flow Build is not accepting Guide input.' };
|
|
3733
3930
|
});
|
|
3734
|
-
|
|
3931
|
+
const stopFlowForTarget = async (targetInput) => {
|
|
3735
3932
|
if (!agent)
|
|
3736
3933
|
return { ok: true, action: 'not_running' };
|
|
3737
3934
|
const target = targetInput
|
|
@@ -3769,7 +3966,8 @@ else {
|
|
|
3769
3966
|
controller.abort(new Error(`Flow interrupted by user: ${flowName}`));
|
|
3770
3967
|
state.flowAgent?.abortActiveKernelRun();
|
|
3771
3968
|
return { ok: true, action: 'stopping', flow: flowName };
|
|
3772
|
-
}
|
|
3969
|
+
};
|
|
3970
|
+
electron_1.ipcMain.handle('flow:stop', async (_event, targetInput) => await stopFlowForTarget(targetInput));
|
|
3773
3971
|
electron_1.ipcMain.handle('agent:readGlobalPrompt', async () => {
|
|
3774
3972
|
if (!agent)
|
|
3775
3973
|
return { error: 'Agent is not initialized' };
|
|
@@ -38,14 +38,18 @@ class ChatCompletionsAdapter {
|
|
|
38
38
|
...(request.systemPrompt ? [{ role: CHAT_SYSTEM_ROLE, content: request.systemPrompt }] : []),
|
|
39
39
|
...(0, chat_messages_1.openAIChatMessages)(request.messages),
|
|
40
40
|
];
|
|
41
|
+
const tools = this.serializeTools(request.tools);
|
|
41
42
|
const body = {
|
|
42
43
|
model: request.model,
|
|
43
44
|
messages,
|
|
44
45
|
temperature: request.temperature,
|
|
45
46
|
max_tokens: request.maxOutputTokens,
|
|
46
|
-
tools: this.serializeTools(request.tools),
|
|
47
|
-
tool_choice: 'auto',
|
|
48
47
|
};
|
|
48
|
+
if (tools.length) {
|
|
49
|
+
body.tools = tools;
|
|
50
|
+
body.tool_choice = 'auto';
|
|
51
|
+
body.parallel_tool_calls = true;
|
|
52
|
+
}
|
|
49
53
|
if (request.reasoningEffort)
|
|
50
54
|
body.reasoning_effort = request.reasoningEffort;
|
|
51
55
|
// 会话标识透传:仅当上层(支持 session_id 语义的 provider)显式填充时写进
|
package/dist/server.d.ts
CHANGED
|
@@ -1,2 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
import { Agent, AgentWorkEvent } from './core/agent';
|
|
2
|
+
import { AutomationManager } from './core/automation';
|
|
3
|
+
export interface HostedMobileServerOptions {
|
|
4
|
+
agent?: Agent;
|
|
5
|
+
automation?: AutomationManager | null;
|
|
6
|
+
/** Mobile-originated runs must reach the already-open desktop renderer. */
|
|
7
|
+
onWorkEvent?: (event: AgentWorkEvent) => void;
|
|
8
|
+
/** Desktop GUI/runtime-pool events must reach mobile SSE subscribers. */
|
|
9
|
+
subscribeWorkEvents?: (listener: (event: AgentWorkEvent) => void) => (() => void);
|
|
10
|
+
/** Read the GUI runtime-pool state for one exact workspace/conversation. */
|
|
11
|
+
conversationUiState?: (target: {
|
|
12
|
+
workspaceId: string;
|
|
13
|
+
conversationId: string;
|
|
14
|
+
}) => Promise<Record<string, unknown>>;
|
|
15
|
+
/** Mutate Goal/Flow state owned by the GUI runtime pool for one exact target. */
|
|
16
|
+
conversationUiAction?: (target: {
|
|
17
|
+
workspaceId: string;
|
|
18
|
+
conversationId: string;
|
|
19
|
+
}, action: 'goal_update' | 'goal_guide' | 'conversation_guide' | 'goal_toggle_pause' | 'goal_clear' | 'flow_pause' | 'flow_resume' | 'flow_guide' | 'conversation_stop' | 'input_mode' | 'queue_enqueue' | 'queue_update' | 'queue_delete' | 'queue_toggle_pause' | 'queue_guide', value?: string, input?: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
20
|
+
/** Send through the same GUI runtime pool used by the desktop renderer. */
|
|
21
|
+
conversationPrompt?: (target: {
|
|
22
|
+
workspaceId: string;
|
|
23
|
+
conversationId: string;
|
|
24
|
+
}, message: string, options?: {
|
|
25
|
+
requestedMode?: string;
|
|
26
|
+
goalObjective?: string;
|
|
27
|
+
inputMode?: string;
|
|
28
|
+
}) => Promise<Record<string, unknown>>;
|
|
29
|
+
}
|
|
30
|
+
/** 托管启动 server(GUI/TUI 内嵌调用;幂等防重入,进程常驻即服务常驻) */
|
|
31
|
+
export declare function runServer(root: string, options?: HostedMobileServerOptions): void;
|
|
32
|
+
/** Attach the GUI-owned automation manager after deferred startup. */
|
|
33
|
+
export declare function setHostedServerAutomation(manager: AutomationManager): void;
|
|
2
34
|
//# sourceMappingURL=server.d.ts.map
|