nexus-agentd 0.1.8 → 0.1.9
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/LICENSE +22 -22
- package/README.md +215 -451
- package/dist/a2a/runtime.d.ts +2 -4
- package/dist/a2a/runtime.js +11 -10
- package/dist/acp/runtime.d.ts +3 -8
- package/dist/acp/runtime.js +42 -69
- package/dist/config.js +1 -15
- package/dist/control-plane.d.ts +0 -1
- package/dist/control-plane.js +1 -19
- package/dist/server.js +63 -248
- package/dist/session-contract.d.ts +2 -2
- package/dist/session.d.ts +9 -2
- package/dist/session.js +150 -16
- package/dist/types.d.ts +9 -45
- package/dist/webui/app.js +912 -1074
- package/dist/webui/icons.d.ts +0 -1
- package/dist/webui/icons.js +0 -1
- package/dist/webui/index.js +10 -10
- package/dist/webui/markup.js +65 -66
- package/dist/webui/styles.js +256 -268
- package/nexus-agentd.example.json +40 -47
- package/package.json +52 -52
- package/dist/agent-instructions.d.ts +0 -11
- package/dist/agent-instructions.js +0 -44
- package/dist/artifact-store.d.ts +0 -41
- package/dist/artifact-store.js +0 -340
- package/dist/workspace-files.d.ts +0 -48
- package/dist/workspace-files.js +0 -269
package/dist/a2a/runtime.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentSessionRuntime, AgentSessionSink } from '../session-contract.js';
|
|
2
|
-
import type { AgentdA2AConfig, AgentdAgentView, AgentdInputAttachment } from '../types.js';
|
|
2
|
+
import type { AgentdA2AConfig, AgentdAgentView, AgentdInputAttachment, AgentdPendingResponse } from '../types.js';
|
|
3
3
|
export declare function probeA2AAgent(id: string, config: AgentdA2AConfig): Promise<AgentdAgentView>;
|
|
4
4
|
export declare class A2AClientRuntime implements AgentSessionRuntime {
|
|
5
5
|
private readonly config;
|
|
@@ -10,8 +10,6 @@ export declare class A2AClientRuntime implements AgentSessionRuntime {
|
|
|
10
10
|
private taskId;
|
|
11
11
|
private contextId;
|
|
12
12
|
private prompting;
|
|
13
|
-
private firstPrompt;
|
|
14
|
-
private readonly instructions;
|
|
15
13
|
private disposed;
|
|
16
14
|
private activeController?;
|
|
17
15
|
private readonly artifactCache;
|
|
@@ -19,7 +17,7 @@ export declare class A2AClientRuntime implements AgentSessionRuntime {
|
|
|
19
17
|
constructor(config: AgentdA2AConfig, sink: AgentSessionSink, promptTimeoutMs: number);
|
|
20
18
|
start(): Promise<void>;
|
|
21
19
|
prompt(message: string, attachments?: AgentdInputAttachment[]): Promise<void>;
|
|
22
|
-
respondPending(
|
|
20
|
+
respondPending(response: AgentdPendingResponse | string, attachments?: AgentdInputAttachment[]): Promise<void>;
|
|
23
21
|
cancel(): Promise<void>;
|
|
24
22
|
dispose(): Promise<void>;
|
|
25
23
|
private messageRequest;
|
package/dist/a2a/runtime.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { Role, TaskState } from '@a2a-js/sdk';
|
|
3
3
|
import { ClientFactory, DefaultAgentCardResolver, JsonRpcTransportFactory, RestTransportFactory } from '@a2a-js/sdk/client';
|
|
4
|
-
import { buildAgentInstructions, composeInitialAgentPrompt } from '../agent-instructions.js';
|
|
5
4
|
export async function probeA2AAgent(id, config) {
|
|
6
5
|
const startedAt = Date.now();
|
|
7
6
|
if (config.enabled === false)
|
|
@@ -44,8 +43,6 @@ export class A2AClientRuntime {
|
|
|
44
43
|
taskId = '';
|
|
45
44
|
contextId = '';
|
|
46
45
|
prompting = false;
|
|
47
|
-
firstPrompt = true;
|
|
48
|
-
instructions;
|
|
49
46
|
disposed = false;
|
|
50
47
|
activeController;
|
|
51
48
|
artifactCache = new Map();
|
|
@@ -54,7 +51,6 @@ export class A2AClientRuntime {
|
|
|
54
51
|
this.config = config;
|
|
55
52
|
this.sink = sink;
|
|
56
53
|
this.promptTimeoutMs = promptTimeoutMs;
|
|
57
|
-
this.instructions = buildAgentInstructions(config.instructions);
|
|
58
54
|
}
|
|
59
55
|
async start() {
|
|
60
56
|
const resolver = createResolver(this.config);
|
|
@@ -82,16 +78,12 @@ export class A2AClientRuntime {
|
|
|
82
78
|
this.prompting = true;
|
|
83
79
|
this.sink.clearPending();
|
|
84
80
|
this.sink.setState('running');
|
|
85
|
-
const promptMessage = this.firstPrompt
|
|
86
|
-
? composeInitialAgentPrompt(this.instructions, message)
|
|
87
|
-
: message;
|
|
88
|
-
this.firstPrompt = false;
|
|
89
81
|
const controller = new AbortController();
|
|
90
82
|
this.activeController = controller;
|
|
91
83
|
const timer = setTimeout(() => controller.abort(new Error('A2A message timed out')), Math.min(this.promptTimeoutMs, this.config.timeoutMs || this.promptTimeoutMs));
|
|
92
84
|
timer.unref?.();
|
|
93
85
|
try {
|
|
94
|
-
const request = this.messageRequest(
|
|
86
|
+
const request = this.messageRequest(message, attachments);
|
|
95
87
|
for await (const response of this.client.sendMessageStream(request, {
|
|
96
88
|
signal: controller.signal
|
|
97
89
|
})) {
|
|
@@ -112,10 +104,19 @@ export class A2AClientRuntime {
|
|
|
112
104
|
this.prompting = false;
|
|
113
105
|
}
|
|
114
106
|
}
|
|
115
|
-
async respondPending(
|
|
107
|
+
async respondPending(response, attachments = []) {
|
|
116
108
|
if (this.sink.state !== 'input_required') {
|
|
117
109
|
throw new Error('A2A session is not waiting for input');
|
|
118
110
|
}
|
|
111
|
+
const message = typeof response === 'string'
|
|
112
|
+
? response
|
|
113
|
+
: response.action === 'cancel'
|
|
114
|
+
? 'cancel'
|
|
115
|
+
: response.action === 'decline'
|
|
116
|
+
? 'decline'
|
|
117
|
+
: response.message ?? response.optionId ?? '';
|
|
118
|
+
if (!message.trim())
|
|
119
|
+
throw new Error('A2A pending response is empty');
|
|
119
120
|
this.sink.clearPending();
|
|
120
121
|
await this.prompt(message, attachments);
|
|
121
122
|
}
|
package/dist/acp/runtime.d.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import type { AgentDriver } from '../drivers/index.js';
|
|
2
2
|
import type { AcpSessionSink } from '../session-contract.js';
|
|
3
|
-
import type { AgentdInputAttachment } from '../types.js';
|
|
4
|
-
export declare class InvalidPermissionAnswerError extends Error {
|
|
5
|
-
constructor(message: string);
|
|
6
|
-
}
|
|
3
|
+
import type { AgentdInputAttachment, AgentdPendingResponse } from '../types.js';
|
|
7
4
|
export declare class AcpProcessRuntime {
|
|
8
5
|
private readonly driver;
|
|
9
6
|
private readonly sink;
|
|
@@ -15,14 +12,12 @@ export declare class AcpProcessRuntime {
|
|
|
15
12
|
private prompting;
|
|
16
13
|
private readonly maxStderrChunkChars;
|
|
17
14
|
private readonly promptTimeoutMs;
|
|
18
|
-
private readonly instructions;
|
|
19
|
-
private firstPrompt;
|
|
20
15
|
private promptCapabilities;
|
|
21
16
|
private inputDirectory?;
|
|
22
|
-
constructor(driver: AgentDriver, sink: AcpSessionSink, maxStderrChunkChars?: number, promptTimeoutMs?: number
|
|
17
|
+
constructor(driver: AgentDriver, sink: AcpSessionSink, maxStderrChunkChars?: number, promptTimeoutMs?: number);
|
|
23
18
|
start(workspace: string): Promise<void>;
|
|
24
19
|
prompt(message: string, attachments?: AgentdInputAttachment[]): Promise<void>;
|
|
25
|
-
respondPending(
|
|
20
|
+
respondPending(input: AgentdPendingResponse | string, _attachments?: AgentdInputAttachment[]): Promise<void>;
|
|
26
21
|
cancel(): Promise<void>;
|
|
27
22
|
dispose(): Promise<void>;
|
|
28
23
|
private requestPermission;
|
package/dist/acp/runtime.js
CHANGED
|
@@ -4,13 +4,6 @@ import path from 'node:path';
|
|
|
4
4
|
import { Readable, Writable } from 'node:stream';
|
|
5
5
|
import { pathToFileURL } from 'node:url';
|
|
6
6
|
import * as acp from '@agentclientprotocol/sdk';
|
|
7
|
-
import { buildAgentInstructions, composeInitialAgentPrompt } from '../agent-instructions.js';
|
|
8
|
-
export class InvalidPermissionAnswerError extends Error {
|
|
9
|
-
constructor(message) {
|
|
10
|
-
super(message);
|
|
11
|
-
this.name = 'InvalidPermissionAnswerError';
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
7
|
export class AcpProcessRuntime {
|
|
15
8
|
driver;
|
|
16
9
|
sink;
|
|
@@ -22,11 +15,9 @@ export class AcpProcessRuntime {
|
|
|
22
15
|
prompting = false;
|
|
23
16
|
maxStderrChunkChars;
|
|
24
17
|
promptTimeoutMs;
|
|
25
|
-
instructions;
|
|
26
|
-
firstPrompt = true;
|
|
27
18
|
promptCapabilities = {};
|
|
28
19
|
inputDirectory;
|
|
29
|
-
constructor(driver, sink, maxStderrChunkChars = 16 * 1024, promptTimeoutMs = 30 * 60 * 1000
|
|
20
|
+
constructor(driver, sink, maxStderrChunkChars = 16 * 1024, promptTimeoutMs = 30 * 60 * 1000) {
|
|
30
21
|
this.driver = driver;
|
|
31
22
|
this.sink = sink;
|
|
32
23
|
const limit = Number.isFinite(maxStderrChunkChars)
|
|
@@ -34,7 +25,6 @@ export class AcpProcessRuntime {
|
|
|
34
25
|
: 16 * 1024;
|
|
35
26
|
this.maxStderrChunkChars = Math.max(1, Math.min(16 * 1024, limit));
|
|
36
27
|
this.promptTimeoutMs = Math.max(10_000, Math.trunc(promptTimeoutMs));
|
|
37
|
-
this.instructions = buildAgentInstructions(customInstructions);
|
|
38
28
|
}
|
|
39
29
|
async start(workspace) {
|
|
40
30
|
if (this.process)
|
|
@@ -96,14 +86,10 @@ export class AcpProcessRuntime {
|
|
|
96
86
|
this.prompting = true;
|
|
97
87
|
this.sink.clearPending();
|
|
98
88
|
this.sink.setState('running');
|
|
99
|
-
const promptMessage = this.firstPrompt
|
|
100
|
-
? composeInitialAgentPrompt(this.instructions, message)
|
|
101
|
-
: message;
|
|
102
|
-
this.firstPrompt = false;
|
|
103
89
|
try {
|
|
104
90
|
const response = await withTimeout(this.connection.agent.request(acp.methods.agent.session.prompt, {
|
|
105
91
|
sessionId,
|
|
106
|
-
prompt: await this.promptBlocks(
|
|
92
|
+
prompt: await this.promptBlocks(message, attachments)
|
|
107
93
|
}), this.promptTimeoutMs, 'ACP prompt timed out');
|
|
108
94
|
if (this.sink.state === 'canceled' || this.sink.state === 'failed') {
|
|
109
95
|
return;
|
|
@@ -129,16 +115,47 @@ export class AcpProcessRuntime {
|
|
|
129
115
|
this.prompting = false;
|
|
130
116
|
}
|
|
131
117
|
}
|
|
132
|
-
async respondPending(
|
|
118
|
+
async respondPending(input, _attachments = []) {
|
|
119
|
+
const response = typeof input === 'string'
|
|
120
|
+
? {
|
|
121
|
+
requestId: this.pendingInput?.request.id ??
|
|
122
|
+
this.pending?.request.id ??
|
|
123
|
+
'',
|
|
124
|
+
message: input
|
|
125
|
+
}
|
|
126
|
+
: input;
|
|
133
127
|
if (this.pendingInput) {
|
|
134
|
-
this.
|
|
128
|
+
if (response.requestId !== this.pendingInput.request.id) {
|
|
129
|
+
throw new Error(`ACP pending request no longer matches: ${response.requestId}`);
|
|
130
|
+
}
|
|
131
|
+
this.finishInput(response.message ?? response.optionId ?? '', response.action);
|
|
135
132
|
return;
|
|
136
133
|
}
|
|
137
134
|
const pending = this.pending;
|
|
138
135
|
if (!pending)
|
|
139
136
|
throw new Error('ACP session is not waiting for input');
|
|
140
|
-
|
|
137
|
+
if (response.requestId !== pending.request.id) {
|
|
138
|
+
throw new Error(`ACP pending request no longer matches: ${response.requestId}`);
|
|
139
|
+
}
|
|
141
140
|
const options = pending.request.options || [];
|
|
141
|
+
if (response.action === 'cancel' || response.action === 'decline') {
|
|
142
|
+
this.finishPermission({ outcome: { outcome: 'cancelled' } });
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (response.action === 'accept') {
|
|
146
|
+
const option = options.find((item) => item.kind?.startsWith('allow')) ||
|
|
147
|
+
options.find((item) => !(item.kind?.startsWith('reject') ?? false));
|
|
148
|
+
if (!option) {
|
|
149
|
+
throw new Error('Permission request does not provide an allow option');
|
|
150
|
+
}
|
|
151
|
+
this.finishPermission({
|
|
152
|
+
outcome: { outcome: 'selected', optionId: option.id }
|
|
153
|
+
});
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const normalized = (response.optionId ?? response.message ?? '')
|
|
157
|
+
.trim()
|
|
158
|
+
.toLowerCase();
|
|
142
159
|
if (['cancel', 'deny', 'reject', '拒绝', '取消', '不同意'].includes(normalized)) {
|
|
143
160
|
this.finishPermission({ outcome: { outcome: 'cancelled' } });
|
|
144
161
|
return;
|
|
@@ -147,9 +164,9 @@ export class AcpProcessRuntime {
|
|
|
147
164
|
const option = Number.isInteger(numeric) && numeric >= 1
|
|
148
165
|
? options[numeric - 1]
|
|
149
166
|
: options.find((item) => item.id.toLowerCase() === normalized ||
|
|
150
|
-
item.name.toLowerCase() === normalized)
|
|
167
|
+
item.name.toLowerCase() === normalized);
|
|
151
168
|
if (!option) {
|
|
152
|
-
throw new
|
|
169
|
+
throw new Error(`Permission answer must be an option id/name or index: ${options
|
|
153
170
|
.map((item, index) => `${index + 1}. ${item.name} (${item.id})`)
|
|
154
171
|
.join('; ')}`);
|
|
155
172
|
}
|
|
@@ -221,18 +238,6 @@ export class AcpProcessRuntime {
|
|
|
221
238
|
}
|
|
222
239
|
: { outcome: { outcome: 'cancelled' } };
|
|
223
240
|
}
|
|
224
|
-
if (this.driver.permissionPolicy === 'allow') {
|
|
225
|
-
const allow = params.options.find((option) => option.kind.toLowerCase() === 'allow_once') ||
|
|
226
|
-
params.options.find((option) => option.kind.toLowerCase().startsWith('allow'));
|
|
227
|
-
return allow
|
|
228
|
-
? {
|
|
229
|
-
outcome: {
|
|
230
|
-
outcome: 'selected',
|
|
231
|
-
optionId: allow.optionId
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
: { outcome: { outcome: 'cancelled' } };
|
|
235
|
-
}
|
|
236
241
|
if (this.pending) {
|
|
237
242
|
return { outcome: { outcome: 'cancelled' } };
|
|
238
243
|
}
|
|
@@ -295,16 +300,17 @@ export class AcpProcessRuntime {
|
|
|
295
300
|
this.pendingInput = { request, params, resolve, timer };
|
|
296
301
|
});
|
|
297
302
|
}
|
|
298
|
-
finishInput(message) {
|
|
303
|
+
finishInput(message, requestedAction) {
|
|
299
304
|
const pending = this.pendingInput;
|
|
300
305
|
if (!pending)
|
|
301
306
|
return;
|
|
302
307
|
const normalized = message.trim().toLowerCase();
|
|
303
308
|
let response;
|
|
304
|
-
if (['cancel', '取消'].includes(normalized)) {
|
|
309
|
+
if (requestedAction === 'cancel' || ['cancel', '取消'].includes(normalized)) {
|
|
305
310
|
response = { action: 'cancel' };
|
|
306
311
|
}
|
|
307
|
-
else if (
|
|
312
|
+
else if (requestedAction === 'decline' ||
|
|
313
|
+
['decline', '拒绝', '不同意'].includes(normalized)) {
|
|
308
314
|
response = { action: 'decline' };
|
|
309
315
|
}
|
|
310
316
|
else if (!isFormElicitation(pending.params)) {
|
|
@@ -477,39 +483,6 @@ export class AcpProcessRuntime {
|
|
|
477
483
|
};
|
|
478
484
|
}
|
|
479
485
|
}
|
|
480
|
-
function permissionApprovalOption(answer, options) {
|
|
481
|
-
const approvals = new Set([
|
|
482
|
-
'yes',
|
|
483
|
-
'y',
|
|
484
|
-
'ok',
|
|
485
|
-
'okay',
|
|
486
|
-
'approve',
|
|
487
|
-
'approved',
|
|
488
|
-
'accept',
|
|
489
|
-
'allow',
|
|
490
|
-
'proceed',
|
|
491
|
-
'同意',
|
|
492
|
-
'允许',
|
|
493
|
-
'允许一次',
|
|
494
|
-
'确认',
|
|
495
|
-
'好的',
|
|
496
|
-
'可以',
|
|
497
|
-
'继续',
|
|
498
|
-
'是',
|
|
499
|
-
'是的'
|
|
500
|
-
]);
|
|
501
|
-
if (!approvals.has(answer))
|
|
502
|
-
return undefined;
|
|
503
|
-
return (options.find((item) => item.kind?.toLowerCase() === 'allow_once') ||
|
|
504
|
-
options.find((item) => isApprovalOption(item)));
|
|
505
|
-
}
|
|
506
|
-
function isApprovalOption(option) {
|
|
507
|
-
const kind = option.kind?.toLowerCase() || '';
|
|
508
|
-
if (kind.startsWith('allow'))
|
|
509
|
-
return true;
|
|
510
|
-
const values = [option.id, option.name].map((value) => value.trim().toLowerCase());
|
|
511
|
-
return values.some((value) => ['allow', 'approve', 'accept', 'permit', '允许', '同意'].some((word) => value === word || value.startsWith(`${word} `) || value.startsWith(`${word}_`)));
|
|
512
|
-
}
|
|
513
486
|
class PromptTimeoutError extends Error {
|
|
514
487
|
}
|
|
515
488
|
function safeFilename(value) {
|
package/dist/config.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { mkdir, open, readFile } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { normalizeAgentInstructions } from './agent-instructions.js';
|
|
4
3
|
import { agentdDriverKinds } from './types.js';
|
|
5
4
|
export async function ensureAgentdConfig(filePath, options = {}) {
|
|
6
5
|
const absolute = path.resolve(filePath);
|
|
@@ -98,12 +97,6 @@ export async function loadAgentdConfig(filePath) {
|
|
|
98
97
|
workspaceRoots,
|
|
99
98
|
maxRequestBytes: integerValue(value.maxRequestBytes, 'maxRequestBytes', 1024 * 1024, 1024, 16 * 1024 * 1024),
|
|
100
99
|
maxAttachmentBytes: integerValue(value.maxAttachmentBytes, 'maxAttachmentBytes', 32 * 1024 * 1024, 1024, 64 * 1024 * 1024),
|
|
101
|
-
artifactStoragePath: resolveConfigPath(absolute, optionalString(value.artifactStoragePath, 'artifactStoragePath') || './artifacts'),
|
|
102
|
-
maxArtifactBytes: integerValue(value.maxArtifactBytes, 'maxArtifactBytes', 512 * 1024 * 1024, 1024, 16 * 1024 * 1024 * 1024),
|
|
103
|
-
maxArtifactStorageBytes: integerValue(value.maxArtifactStorageBytes, 'maxArtifactStorageBytes', 4 * 1024 * 1024 * 1024, 1024 * 1024, Number.MAX_SAFE_INTEGER),
|
|
104
|
-
maxPublishedArtifacts: integerValue(value.maxPublishedArtifacts, 'maxPublishedArtifacts', 4096, 1, 1_000_000),
|
|
105
|
-
maxConcurrentArtifactPublishes: integerValue(value.maxConcurrentArtifactPublishes, 'maxConcurrentArtifactPublishes', 4, 1, 128),
|
|
106
|
-
artifactTtlMs: integerValue(value.artifactTtlMs, 'artifactTtlMs', 24 * 60 * 60 * 1000, 60_000, 30 * 24 * 60 * 60 * 1000),
|
|
107
100
|
maxEventsPerSession: integerValue(value.maxEventsPerSession, 'maxEventsPerSession', 2048, 64, 100_000),
|
|
108
101
|
maxOutputChars: integerValue(value.maxOutputChars, 'maxOutputChars', 512 * 1024, 16 * 1024, 16 * 1024 * 1024),
|
|
109
102
|
sessionTtlMs: integerValue(value.sessionTtlMs, 'sessionTtlMs', 24 * 60 * 60 * 1000, 60_000, 30 * 24 * 60 * 60 * 1000),
|
|
@@ -141,9 +134,7 @@ function parseAgent(id, value) {
|
|
|
141
134
|
throw new Error(`Unsupported nexus-agentd driver: ${driver || id}`);
|
|
142
135
|
}
|
|
143
136
|
const permissionPolicy = optionalString(input.permissionPolicy, `agents.${id}.permissionPolicy`) || 'ask';
|
|
144
|
-
if (permissionPolicy !== 'ask' &&
|
|
145
|
-
permissionPolicy !== 'allow' &&
|
|
146
|
-
permissionPolicy !== 'deny') {
|
|
137
|
+
if (permissionPolicy !== 'ask' && permissionPolicy !== 'deny') {
|
|
147
138
|
throw new Error(`Invalid permissionPolicy for ${id}`);
|
|
148
139
|
}
|
|
149
140
|
const result = {
|
|
@@ -151,7 +142,6 @@ function parseAgent(id, value) {
|
|
|
151
142
|
driver,
|
|
152
143
|
name: optionalString(input.name, `agents.${id}.name`),
|
|
153
144
|
description: optionalString(input.description, `agents.${id}.description`),
|
|
154
|
-
instructions: normalizeAgentInstructions(input.instructions, `agents.${id}.instructions`),
|
|
155
145
|
enabled: optionalBoolean(input.enabled, `agents.${id}.enabled`) ?? true,
|
|
156
146
|
workspace: optionalString(input.workspace, `agents.${id}.workspace`),
|
|
157
147
|
command: optionalString(input.command, `agents.${id}.command`),
|
|
@@ -207,7 +197,6 @@ function parseA2AAgent(id, input) {
|
|
|
207
197
|
protocol: 'a2a',
|
|
208
198
|
name: optionalString(input.name, `agents.${id}.name`),
|
|
209
199
|
description: optionalString(input.description, `agents.${id}.description`),
|
|
210
|
-
instructions: normalizeAgentInstructions(input.instructions, `agents.${id}.instructions`),
|
|
211
200
|
enabled: optionalBoolean(input.enabled, `agents.${id}.enabled`) ?? true,
|
|
212
201
|
agentCardUrl,
|
|
213
202
|
agentUrl,
|
|
@@ -340,9 +329,6 @@ function validateHttpUrl(value, name) {
|
|
|
340
329
|
throw new Error(`nexus-agentd ${name} must be an http(s) URL without credentials or a fragment`);
|
|
341
330
|
}
|
|
342
331
|
}
|
|
343
|
-
function resolveConfigPath(configPath, value) {
|
|
344
|
-
return path.resolve(path.dirname(configPath), value);
|
|
345
|
-
}
|
|
346
332
|
function secretsEqual(left, right) {
|
|
347
333
|
return left.length === right.length && left === right;
|
|
348
334
|
}
|
package/dist/control-plane.d.ts
CHANGED
package/dist/control-plane.js
CHANGED
|
@@ -2,7 +2,6 @@ import { randomBytes, randomUUID, timingSafeEqual } from 'node:crypto';
|
|
|
2
2
|
import { chmod, open, readFile, rename, rm } from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { hashAdminPassword, validateAdminPassword, verifyAdminPassword } from './auth.js';
|
|
5
|
-
import { normalizeAgentInstructions } from './agent-instructions.js';
|
|
6
5
|
import { loadAgentdConfig } from './config.js';
|
|
7
6
|
import { createDriverRegistry } from './drivers/index.js';
|
|
8
7
|
import { agentdDriverKinds } from './types.js';
|
|
@@ -312,7 +311,6 @@ export class AgentdControlPlane {
|
|
|
312
311
|
next.name = cleanString(update.name) || cleanString(previous.name);
|
|
313
312
|
}
|
|
314
313
|
}
|
|
315
|
-
setOptionalInstructions(next, update.instructions ?? cleanString(previous.instructions));
|
|
316
314
|
setOptionalString(next, 'description', update.description ?? cleanString(previous.description));
|
|
317
315
|
agents[id] = next;
|
|
318
316
|
raw.agents = agents;
|
|
@@ -450,7 +448,6 @@ export class AgentdControlPlane {
|
|
|
450
448
|
protocol: 'a2a',
|
|
451
449
|
name: config.name || id,
|
|
452
450
|
description: config.description,
|
|
453
|
-
instructions: config.instructions,
|
|
454
451
|
enabled: config.enabled !== false,
|
|
455
452
|
agentCardUrl: config.agentCardUrl || defaultAgentCardUrl(config.agentUrl),
|
|
456
453
|
agentUrl: config.agentUrl,
|
|
@@ -469,7 +466,6 @@ export class AgentdControlPlane {
|
|
|
469
466
|
driver: config.driver,
|
|
470
467
|
name: config.name || id,
|
|
471
468
|
description: config.description,
|
|
472
|
-
instructions: config.instructions,
|
|
473
469
|
enabled: config.enabled !== false,
|
|
474
470
|
workspace: config.workspace || this.config.workspaceRoots[0] || '',
|
|
475
471
|
permissionPolicy: config.permissionPolicy || 'ask',
|
|
@@ -505,9 +501,8 @@ function validateUpdate(update) {
|
|
|
505
501
|
}
|
|
506
502
|
if (update.permissionPolicy !== undefined &&
|
|
507
503
|
update.permissionPolicy !== 'ask' &&
|
|
508
|
-
update.permissionPolicy !== 'allow' &&
|
|
509
504
|
update.permissionPolicy !== 'deny') {
|
|
510
|
-
throw new ControlPlaneError(400, 'permissionPolicy must be ask
|
|
505
|
+
throw new ControlPlaneError(400, 'permissionPolicy must be ask or deny');
|
|
511
506
|
}
|
|
512
507
|
if (update.preferredTransport !== undefined &&
|
|
513
508
|
!['auto', 'jsonrpc', 'http-json'].includes(update.preferredTransport)) {
|
|
@@ -612,19 +607,6 @@ function setOptionalString(target, key, value) {
|
|
|
612
607
|
else
|
|
613
608
|
delete target[key];
|
|
614
609
|
}
|
|
615
|
-
function setOptionalInstructions(target, value) {
|
|
616
|
-
let text;
|
|
617
|
-
try {
|
|
618
|
-
text = normalizeAgentInstructions(value);
|
|
619
|
-
}
|
|
620
|
-
catch (error) {
|
|
621
|
-
throw new ControlPlaneError(400, errorMessage(error));
|
|
622
|
-
}
|
|
623
|
-
if (text)
|
|
624
|
-
target.instructions = text;
|
|
625
|
-
else
|
|
626
|
-
delete target.instructions;
|
|
627
|
-
}
|
|
628
610
|
function validHeaderName(value) {
|
|
629
611
|
return /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(value);
|
|
630
612
|
}
|