@pellux/goodvibes-agent 1.0.31 → 1.0.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +59 -2
- package/README.md +72 -58
- package/dist/package/main.js +7572 -2430
- package/docs/README.md +25 -21
- package/docs/channels-remote-and-api.md +6 -2
- package/docs/connected-host.md +27 -6
- package/docs/getting-started.md +87 -66
- package/docs/knowledge-artifacts-and-multimodal.md +16 -4
- package/docs/project-planning.md +2 -2
- package/docs/providers-and-routing.md +3 -2
- package/docs/release-and-publishing.md +15 -11
- package/docs/tools-and-commands.md +150 -128
- package/docs/voice-and-live-tts.md +1 -1
- package/package.json +8 -3
- package/release/live-verification/live-verification.json +148 -0
- package/release/live-verification/live-verification.md +187 -0
- package/release/performance-snapshot.json +57 -0
- package/release/release-notes.md +19 -0
- package/release/release-readiness.json +581 -0
- package/src/agent/harness-control.ts +42 -3
- package/src/cli/agent-knowledge-command.ts +5 -5
- package/src/cli/agent-knowledge-format.ts +11 -0
- package/src/cli/agent-knowledge-runtime.ts +92 -13
- package/src/cli/bundle-command.ts +5 -4
- package/src/cli/entrypoint.ts +5 -2
- package/src/cli/external-runtime.ts +2 -15
- package/src/cli/management.ts +4 -3
- package/src/input/commands/guidance-runtime.ts +1 -1
- package/src/input/commands/knowledge.ts +2 -2
- package/src/runtime/bootstrap.ts +10 -18
- package/src/runtime/connected-host-auth.ts +16 -0
- package/src/tools/agent-analysis-registry-policy.ts +2 -9
- package/src/tools/agent-channel-send-tool.ts +3 -9
- package/src/tools/agent-context-policy.ts +1 -5
- package/src/tools/agent-find-policy.ts +1 -4
- package/src/tools/agent-harness-channel-metadata.ts +177 -0
- package/src/tools/agent-harness-cli-metadata.ts +4 -1
- package/src/tools/agent-harness-command-catalog.ts +10 -3
- package/src/tools/agent-harness-connected-host-status.ts +9 -3
- package/src/tools/agent-harness-delegation-posture.ts +216 -0
- package/src/tools/agent-harness-keybinding-metadata.ts +57 -22
- package/src/tools/agent-harness-mcp-metadata.ts +248 -0
- package/src/tools/agent-harness-media-posture.ts +282 -0
- package/src/tools/agent-harness-metadata.ts +44 -9
- package/src/tools/agent-harness-model-routing.ts +501 -0
- package/src/tools/agent-harness-model-tool-catalog.ts +7 -2
- package/src/tools/agent-harness-notification-metadata.ts +217 -0
- package/src/tools/agent-harness-operator-methods.ts +285 -0
- package/src/tools/agent-harness-pairing-posture.ts +265 -0
- package/src/tools/agent-harness-panel-metadata.ts +26 -12
- package/src/tools/agent-harness-provider-account-metadata.ts +205 -0
- package/src/tools/agent-harness-release-evidence.ts +364 -0
- package/src/tools/agent-harness-release-readiness.ts +298 -0
- package/src/tools/agent-harness-security-posture.ts +648 -0
- package/src/tools/agent-harness-service-posture.ts +207 -0
- package/src/tools/agent-harness-session-metadata.ts +284 -0
- package/src/tools/agent-harness-setup-posture.ts +295 -0
- package/src/tools/agent-harness-tool-schema.ts +104 -27
- package/src/tools/agent-harness-tool.ts +251 -235
- package/src/tools/agent-harness-ui-surface-metadata.ts +20 -12
- package/src/tools/agent-harness-workspace-actions.ts +260 -0
- package/src/tools/agent-knowledge-ingest-tool.ts +4 -10
- package/src/tools/agent-knowledge-tool.ts +120 -25
- package/src/tools/agent-local-registry-tool.ts +3 -7
- package/src/tools/agent-media-generate-tool.ts +2 -8
- package/src/tools/agent-notify-tool.ts +3 -8
- package/src/tools/agent-operator-action-tool.ts +4 -10
- package/src/tools/agent-operator-briefing-tool.ts +1 -6
- package/src/tools/agent-read-policy.ts +1 -4
- package/src/tools/agent-reminder-schedule-tool.ts +4 -9
- package/src/tools/agent-tool-policy-guard.ts +15 -51
- package/src/tools/agent-web-search-policy.ts +1 -4
- package/src/tools/agent-work-plan-tool.ts +1 -6
- package/src/version.ts +2 -2
|
@@ -77,6 +77,18 @@ export interface HarnessSettingDescriptor {
|
|
|
77
77
|
readonly lookup?: HarnessSettingLookup;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
export interface HarnessSettingSummary {
|
|
81
|
+
readonly key: string;
|
|
82
|
+
readonly category: string;
|
|
83
|
+
readonly type: ConfigSetting['type'];
|
|
84
|
+
readonly value: unknown;
|
|
85
|
+
readonly configured: boolean;
|
|
86
|
+
readonly writable: boolean;
|
|
87
|
+
readonly visibleInWorkspace: boolean;
|
|
88
|
+
readonly summary: string;
|
|
89
|
+
readonly enumValues?: readonly string[];
|
|
90
|
+
}
|
|
91
|
+
|
|
80
92
|
export interface HarnessSettingMutationResult {
|
|
81
93
|
readonly key: string;
|
|
82
94
|
readonly action: 'set' | 'reset';
|
|
@@ -91,6 +103,11 @@ function valuesEqual(left: unknown, right: unknown): boolean {
|
|
|
91
103
|
return JSON.stringify(left) === JSON.stringify(right);
|
|
92
104
|
}
|
|
93
105
|
|
|
106
|
+
function previewText(value: string, maxLength = 120): string {
|
|
107
|
+
const normalized = value.replace(/\s+/g, ' ').trim();
|
|
108
|
+
return normalized.length <= maxLength ? normalized : `${normalized.slice(0, maxLength - 1).trimEnd()}...`;
|
|
109
|
+
}
|
|
110
|
+
|
|
94
111
|
function clampLimit(value: unknown, fallback = DEFAULT_SETTING_LIMIT): number {
|
|
95
112
|
if (typeof value !== 'number' || !Number.isFinite(value)) return fallback;
|
|
96
113
|
return Math.max(1, Math.min(500, Math.trunc(value)));
|
|
@@ -164,10 +181,30 @@ export function describeHarnessSetting(
|
|
|
164
181
|
};
|
|
165
182
|
}
|
|
166
183
|
|
|
184
|
+
export function describeHarnessSettingSummary(
|
|
185
|
+
configManager: Pick<ConfigManager, 'get'>,
|
|
186
|
+
setting: ConfigSetting,
|
|
187
|
+
): HarnessSettingSummary {
|
|
188
|
+
const value = configManager.get(setting.key as ConfigKey);
|
|
189
|
+
const hostOwned = isExternalHostOwnedSettingKey(setting.key);
|
|
190
|
+
return {
|
|
191
|
+
key: setting.key,
|
|
192
|
+
category: setting.key.split('.')[0] ?? '',
|
|
193
|
+
type: setting.type,
|
|
194
|
+
value: redactHarnessSettingValue(setting.key, value),
|
|
195
|
+
configured: !valuesEqual(value, setting.default),
|
|
196
|
+
writable: !hostOwned,
|
|
197
|
+
visibleInWorkspace: !isAgentHiddenSettingKey(setting.key),
|
|
198
|
+
summary: previewText(setting.description),
|
|
199
|
+
...(setting.enumValues ? { enumValues: setting.enumValues } : {}),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
167
203
|
export function listHarnessSettings(
|
|
168
204
|
configManager: Pick<ConfigManager, 'get' | 'getSchema'>,
|
|
169
205
|
filters: HarnessSettingFilters = {},
|
|
170
|
-
|
|
206
|
+
options: { readonly includeParameters?: boolean } = {},
|
|
207
|
+
): readonly (HarnessSettingDescriptor | HarnessSettingSummary)[] {
|
|
171
208
|
const key = filters.key?.trim();
|
|
172
209
|
const category = filters.category?.trim();
|
|
173
210
|
const prefix = filters.prefix?.trim();
|
|
@@ -185,7 +222,9 @@ export function listHarnessSettings(
|
|
|
185
222
|
}
|
|
186
223
|
return true;
|
|
187
224
|
})
|
|
188
|
-
.map((setting) =>
|
|
225
|
+
.map((setting) => options.includeParameters
|
|
226
|
+
? describeHarnessSetting(configManager, setting)
|
|
227
|
+
: describeHarnessSettingSummary(configManager, setting))
|
|
189
228
|
.slice(0, limit);
|
|
190
229
|
}
|
|
191
230
|
|
|
@@ -358,7 +397,7 @@ export async function resetHarnessSetting(
|
|
|
358
397
|
};
|
|
359
398
|
}
|
|
360
399
|
|
|
361
|
-
export function formatHarnessSettingList(settings: readonly HarnessSettingDescriptor[]): string {
|
|
400
|
+
export function formatHarnessSettingList(settings: readonly (HarnessSettingDescriptor | HarnessSettingSummary)[]): string {
|
|
362
401
|
if (settings.length === 0) return 'No settings matched.';
|
|
363
402
|
return [
|
|
364
403
|
`Settings (${settings.length})`,
|
|
@@ -160,7 +160,7 @@ export async function handleAgentKnowledgeCommand(runtime: CliCommandRuntime): P
|
|
|
160
160
|
const [id] = commandValues(rest);
|
|
161
161
|
if (!id) return { output: 'Usage: goodvibes-agent knowledge get <source|node|issue id>', exitCode: 2 };
|
|
162
162
|
const route = `/api/goodvibes-agent/knowledge/items/${encodeURIComponent(id)}`;
|
|
163
|
-
const result = await runKnowledgeCall(runtime, AGENT_KNOWLEDGE_METHODS.itemGet, async (connection) => (
|
|
163
|
+
const result = await runKnowledgeCall(runtime, { ...AGENT_KNOWLEDGE_METHODS.itemGet, route }, async (connection) => (
|
|
164
164
|
await getAgentKnowledgeJson(connection, route)
|
|
165
165
|
));
|
|
166
166
|
if (!result.ok) return { output: formatFailure(result, json), exitCode: 1 };
|
|
@@ -189,7 +189,7 @@ export async function handleAgentKnowledgeCommand(runtime: CliCommandRuntime): P
|
|
|
189
189
|
const id = values[1];
|
|
190
190
|
if (!id) return { output: 'Usage: goodvibes-agent knowledge connectors doctor <connectorId>', exitCode: 2 };
|
|
191
191
|
const route = `/api/goodvibes-agent/knowledge/connectors/${encodeURIComponent(id)}/doctor`;
|
|
192
|
-
const result = await runKnowledgeCall(runtime, AGENT_KNOWLEDGE_METHODS.connectorDoctor, async (connection) => (
|
|
192
|
+
const result = await runKnowledgeCall(runtime, { ...AGENT_KNOWLEDGE_METHODS.connectorDoctor, route }, async (connection) => (
|
|
193
193
|
await getAgentKnowledgeJson(connection, route)
|
|
194
194
|
));
|
|
195
195
|
if (!result.ok) return { output: formatFailure(result, json), exitCode: 1 };
|
|
@@ -201,7 +201,7 @@ export async function handleAgentKnowledgeCommand(runtime: CliCommandRuntime): P
|
|
|
201
201
|
const id = values[0];
|
|
202
202
|
if (id) {
|
|
203
203
|
const route = `/api/goodvibes-agent/knowledge/connectors/${encodeURIComponent(id)}`;
|
|
204
|
-
const result = await runKnowledgeCall(runtime, AGENT_KNOWLEDGE_METHODS.connectorGet, async (connection) => (
|
|
204
|
+
const result = await runKnowledgeCall(runtime, { ...AGENT_KNOWLEDGE_METHODS.connectorGet, route }, async (connection) => (
|
|
205
205
|
await getAgentKnowledgeJson(connection, route)
|
|
206
206
|
));
|
|
207
207
|
if (!result.ok) return { output: formatFailure(result, json), exitCode: 1 };
|
|
@@ -224,7 +224,7 @@ export async function handleAgentKnowledgeCommand(runtime: CliCommandRuntime): P
|
|
|
224
224
|
const [id] = commandValues(rest);
|
|
225
225
|
if (!id) return { output: 'Usage: goodvibes-agent knowledge connector <connectorId>', exitCode: 2 };
|
|
226
226
|
const route = `/api/goodvibes-agent/knowledge/connectors/${encodeURIComponent(id)}`;
|
|
227
|
-
const result = await runKnowledgeCall(runtime, AGENT_KNOWLEDGE_METHODS.connectorGet, async (connection) => (
|
|
227
|
+
const result = await runKnowledgeCall(runtime, { ...AGENT_KNOWLEDGE_METHODS.connectorGet, route }, async (connection) => (
|
|
228
228
|
await getAgentKnowledgeJson(connection, route)
|
|
229
229
|
));
|
|
230
230
|
if (!result.ok) return { output: formatFailure(result, json), exitCode: 1 };
|
|
@@ -238,7 +238,7 @@ export async function handleAgentKnowledgeCommand(runtime: CliCommandRuntime): P
|
|
|
238
238
|
const [id] = commandValues(rest);
|
|
239
239
|
if (!id) return { output: 'Usage: goodvibes-agent knowledge connector-doctor <connectorId>', exitCode: 2 };
|
|
240
240
|
const route = `/api/goodvibes-agent/knowledge/connectors/${encodeURIComponent(id)}/doctor`;
|
|
241
|
-
const result = await runKnowledgeCall(runtime, AGENT_KNOWLEDGE_METHODS.connectorDoctor, async (connection) => (
|
|
241
|
+
const result = await runKnowledgeCall(runtime, { ...AGENT_KNOWLEDGE_METHODS.connectorDoctor, route }, async (connection) => (
|
|
242
242
|
await getAgentKnowledgeJson(connection, route)
|
|
243
243
|
));
|
|
244
244
|
if (!result.ok) return { output: formatFailure(result, json), exitCode: 1 };
|
|
@@ -47,6 +47,7 @@ export function formatAgentKnowledgeFailureKind(kind: string): string {
|
|
|
47
47
|
if (kind === 'connected_host_unavailable') return 'connected host unavailable';
|
|
48
48
|
if (kind === 'connected_host_route_unavailable') return 'connected host route unavailable';
|
|
49
49
|
if (kind === 'connected_host_error') return 'connected host error';
|
|
50
|
+
if (kind === 'scope_contamination') return 'scope contamination';
|
|
50
51
|
if (kind === 'version_mismatch') return 'version mismatch';
|
|
51
52
|
return kind.replace(/[_-]+/g, ' ');
|
|
52
53
|
}
|
|
@@ -163,6 +164,7 @@ export function formatEntityList(data: unknown, kind: 'sources' | 'nodes' | 'iss
|
|
|
163
164
|
...values.slice(0, limit).map((value, index) => (
|
|
164
165
|
kind === 'issues' ? format(value) : ` ${index + 1}. ${format(value)}`
|
|
165
166
|
)),
|
|
167
|
+
` route /api/goodvibes-agent/knowledge/${kind}`,
|
|
166
168
|
].join('\n');
|
|
167
169
|
}
|
|
168
170
|
|
|
@@ -179,6 +181,7 @@ export function formatItem(data: unknown, id: string): string {
|
|
|
179
181
|
`Agent Knowledge item ${id}`,
|
|
180
182
|
` ${sourceLine(source)}`,
|
|
181
183
|
relatedKnowledgeCountsLine(relatedEdges, linkedSources, linkedNodes),
|
|
184
|
+
' route /api/goodvibes-agent/knowledge/items/{id}',
|
|
182
185
|
].join('\n');
|
|
183
186
|
}
|
|
184
187
|
if (node) {
|
|
@@ -186,6 +189,7 @@ export function formatItem(data: unknown, id: string): string {
|
|
|
186
189
|
`Agent Knowledge item ${id}`,
|
|
187
190
|
` ${nodeLine(node)}`,
|
|
188
191
|
relatedKnowledgeCountsLine(relatedEdges, linkedSources, linkedNodes),
|
|
192
|
+
' route /api/goodvibes-agent/knowledge/items/{id}',
|
|
189
193
|
].join('\n');
|
|
190
194
|
}
|
|
191
195
|
if (issue) {
|
|
@@ -193,6 +197,7 @@ export function formatItem(data: unknown, id: string): string {
|
|
|
193
197
|
`Agent Knowledge item ${id}`,
|
|
194
198
|
issueLine(issue),
|
|
195
199
|
relatedKnowledgeCountsLine(relatedEdges, linkedSources, linkedNodes),
|
|
200
|
+
' route /api/goodvibes-agent/knowledge/items/{id}',
|
|
196
201
|
].join('\n');
|
|
197
202
|
}
|
|
198
203
|
return [
|
|
@@ -231,6 +236,7 @@ export function formatConnectors(data: unknown): string {
|
|
|
231
236
|
return [
|
|
232
237
|
`Agent Knowledge connectors (${connectors.length})`,
|
|
233
238
|
...connectors.map(connectorLine),
|
|
239
|
+
' route /api/goodvibes-agent/knowledge/connectors',
|
|
234
240
|
].join('\n');
|
|
235
241
|
}
|
|
236
242
|
|
|
@@ -299,6 +305,7 @@ export function formatAsk(data: unknown, query: string): string {
|
|
|
299
305
|
}
|
|
300
306
|
if (facts.length > 0) lines.push('', `Facts ${facts.length}`);
|
|
301
307
|
if (gaps.length > 0) lines.push('', `Gaps ${gaps.length}`);
|
|
308
|
+
lines.push('', 'route /api/goodvibes-agent/knowledge/ask');
|
|
302
309
|
return lines.join('\n');
|
|
303
310
|
}
|
|
304
311
|
|
|
@@ -316,6 +323,7 @@ export function formatSearch(data: unknown, query: string): string {
|
|
|
316
323
|
return [
|
|
317
324
|
`Agent Knowledge search ${query}`,
|
|
318
325
|
...results.slice(0, 10).map((result, index) => ` ${index + 1}. ${resultLine(result)}`),
|
|
326
|
+
' route /api/goodvibes-agent/knowledge/search',
|
|
319
327
|
].join('\n');
|
|
320
328
|
}
|
|
321
329
|
|
|
@@ -385,5 +393,8 @@ export function formatFailure(failure: AgentKnowledgeFailureLike, json: boolean)
|
|
|
385
393
|
failure.kind === 'connected_host_route_unavailable'
|
|
386
394
|
? ' next update the connected GoodVibes host to the SDK version required by this Agent package.'
|
|
387
395
|
: null,
|
|
396
|
+
failure.kind === 'scope_contamination'
|
|
397
|
+
? ' next update the connected GoodVibes host so Agent Knowledge routes return only Agent-owned scope data.'
|
|
398
|
+
: null,
|
|
388
399
|
].filter((line): line is string => Boolean(line)).join('\n');
|
|
389
400
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
1
|
import { createBrowserAgentSdk } from '@pellux/goodvibes-sdk/browser/agent';
|
|
4
2
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
5
3
|
import { SDK_VERSION, VERSION } from '../version.ts';
|
|
4
|
+
import { readConnectedHostOperatorToken } from '../runtime/connected-host-auth.ts';
|
|
6
5
|
import type { ConnectedHostCallMethod } from './agent-knowledge-methods.ts';
|
|
7
6
|
|
|
8
7
|
export type JsonRecord = Record<string, unknown>;
|
|
@@ -22,7 +21,13 @@ export interface AgentKnowledgeConnectionRuntime {
|
|
|
22
21
|
|
|
23
22
|
export interface AgentKnowledgeFailure {
|
|
24
23
|
readonly ok: false;
|
|
25
|
-
readonly kind:
|
|
24
|
+
readonly kind:
|
|
25
|
+
| 'connected_host_unavailable'
|
|
26
|
+
| 'auth_required'
|
|
27
|
+
| 'version_mismatch'
|
|
28
|
+
| 'connected_host_route_unavailable'
|
|
29
|
+
| 'connected_host_error'
|
|
30
|
+
| 'scope_contamination';
|
|
26
31
|
readonly error: string;
|
|
27
32
|
readonly baseUrl: string;
|
|
28
33
|
readonly route: string;
|
|
@@ -56,15 +61,8 @@ export function resolveConnectedHostConnection(runtime: AgentKnowledgeConnection
|
|
|
56
61
|
const host = String(runtime.configManager.get('controlPlane.host') ?? '127.0.0.1');
|
|
57
62
|
const port = Number(runtime.configManager.get('controlPlane.port') ?? 3421);
|
|
58
63
|
const baseUrl = `http://${host}:${Number.isFinite(port) ? port : 3421}`;
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
try {
|
|
62
|
-
const parsed = JSON.parse(readFileSync(tokenPath, 'utf-8')) as unknown;
|
|
63
|
-
const token = isRecord(parsed) && typeof parsed.token === 'string' ? parsed.token : null;
|
|
64
|
-
return { baseUrl, token, tokenPath };
|
|
65
|
-
} catch {
|
|
66
|
-
return { baseUrl, token: null, tokenPath };
|
|
67
|
-
}
|
|
64
|
+
const token = readConnectedHostOperatorToken(runtime.homeDirectory);
|
|
65
|
+
return { baseUrl, token: token.token, tokenPath: token.path };
|
|
68
66
|
}
|
|
69
67
|
|
|
70
68
|
export async function fetchConnectedHostStatus(connection: AgentKnowledgeConnection): Promise<{ readonly ok: boolean; readonly status: number; readonly body: unknown }> {
|
|
@@ -122,6 +120,87 @@ export function createAgentSdk(connection: AgentKnowledgeConnection) {
|
|
|
122
120
|
});
|
|
123
121
|
}
|
|
124
122
|
|
|
123
|
+
const AGENT_KNOWLEDGE_SCOPE_KEYS = new Set(['spaceid', 'knowledgespaceid']);
|
|
124
|
+
const AGENT_KNOWLEDGE_SCOPE_TEXT_PATTERNS: readonly { readonly label: string; readonly pattern: RegExp }[] = [
|
|
125
|
+
{
|
|
126
|
+
label: 'default knowledge scope id',
|
|
127
|
+
pattern: /["']?(?:knowledge[-_\s]*space[-_\s]*id|knowledgespaceid|space[-_\s]*id|spaceid)["']?\s*[:=]\s*["']?default["']?/i,
|
|
128
|
+
},
|
|
129
|
+
{ label: 'host assistant payload marker', pattern: /home\s*assistant/i },
|
|
130
|
+
{ label: 'host graph payload marker', pattern: /home\s*graph|homegraph/i },
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
function normalizedJsonKey(key: string): string {
|
|
134
|
+
return key.replace(/[-_\s]/g, '').toLowerCase();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function findAgentKnowledgeTextContamination(value: string): string | null {
|
|
138
|
+
for (const { label, pattern } of AGENT_KNOWLEDGE_SCOPE_TEXT_PATTERNS) {
|
|
139
|
+
if (pattern.test(value)) return label;
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function findAgentKnowledgeScopeContamination(value: unknown): string | null {
|
|
145
|
+
const seen = new WeakSet<object>();
|
|
146
|
+
const visit = (node: unknown): string | null => {
|
|
147
|
+
if (typeof node === 'string') return findAgentKnowledgeTextContamination(node);
|
|
148
|
+
if (!node || typeof node !== 'object') return null;
|
|
149
|
+
if (seen.has(node)) return null;
|
|
150
|
+
seen.add(node);
|
|
151
|
+
if (Array.isArray(node)) {
|
|
152
|
+
for (const item of node) {
|
|
153
|
+
const nested = visit(item);
|
|
154
|
+
if (nested) return nested;
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
for (const [key, nestedValue] of Object.entries(node as JsonRecord)) {
|
|
159
|
+
const keyFinding = findAgentKnowledgeTextContamination(key);
|
|
160
|
+
if (keyFinding && keyFinding !== 'default knowledge scope id') return keyFinding;
|
|
161
|
+
const normalizedKey = normalizedJsonKey(key);
|
|
162
|
+
if (
|
|
163
|
+
AGENT_KNOWLEDGE_SCOPE_KEYS.has(normalizedKey)
|
|
164
|
+
&& typeof nestedValue === 'string'
|
|
165
|
+
&& nestedValue.trim().toLowerCase() === 'default'
|
|
166
|
+
) {
|
|
167
|
+
return `${key}=default`;
|
|
168
|
+
}
|
|
169
|
+
const nested = visit(nestedValue);
|
|
170
|
+
if (nested) return nested;
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
};
|
|
174
|
+
return visit(value);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function agentKnowledgeScopeContaminationFailure(
|
|
178
|
+
connection: AgentKnowledgeConnection,
|
|
179
|
+
route: string,
|
|
180
|
+
finding: string,
|
|
181
|
+
): AgentKnowledgeFailure {
|
|
182
|
+
return {
|
|
183
|
+
ok: false,
|
|
184
|
+
kind: 'scope_contamination',
|
|
185
|
+
error: [
|
|
186
|
+
`Agent Knowledge route returned non-Agent knowledge contamination (${finding}).`,
|
|
187
|
+
'GoodVibes Agent must use only isolated /api/goodvibes-agent/knowledge/* scope data.',
|
|
188
|
+
].join(' '),
|
|
189
|
+
baseUrl: connection.baseUrl,
|
|
190
|
+
route,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function validateAgentKnowledgeData<TData>(
|
|
195
|
+
data: TData,
|
|
196
|
+
connection: AgentKnowledgeConnection,
|
|
197
|
+
method: ConnectedHostCallMethod,
|
|
198
|
+
): AgentKnowledgeResult<TData> {
|
|
199
|
+
const contamination = findAgentKnowledgeScopeContamination(data);
|
|
200
|
+
if (contamination) return agentKnowledgeScopeContaminationFailure(connection, method.route, contamination);
|
|
201
|
+
return { ok: true, kind: method.kind, route: method.route, data };
|
|
202
|
+
}
|
|
203
|
+
|
|
125
204
|
export async function postAgentKnowledgeJson<TData>(
|
|
126
205
|
connection: AgentKnowledgeConnection,
|
|
127
206
|
route: string,
|
|
@@ -239,7 +318,7 @@ export async function runKnowledgeCall<TData>(
|
|
|
239
318
|
}
|
|
240
319
|
try {
|
|
241
320
|
const data = await call(connection);
|
|
242
|
-
return
|
|
321
|
+
return validateAgentKnowledgeData(data, connection, method);
|
|
243
322
|
} catch (error) {
|
|
244
323
|
return classifyKnowledgeError(error, connection, method.route);
|
|
245
324
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { dirname
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
3
|
import { RuntimeEventBus } from '@/runtime/index.ts';
|
|
4
4
|
import { createShellPathService } from '@/runtime/index.ts';
|
|
5
5
|
import { listProviderRuntimeSnapshots } from '@pellux/goodvibes-sdk/platform/providers';
|
|
6
6
|
import { createRuntimeServices } from '../runtime/services.ts';
|
|
7
7
|
import { createRuntimeStore } from '../runtime/store/index.ts';
|
|
8
|
+
import { readConnectedHostOperatorToken } from '../runtime/connected-host-auth.ts';
|
|
8
9
|
import { getOnboardingCheckMarkerPath } from '../runtime/onboarding/index.ts';
|
|
9
10
|
import { CONFIG_SCHEMA } from '../config/index.ts';
|
|
10
11
|
import { SecretsManager } from '../config/secrets.ts';
|
|
@@ -76,14 +77,14 @@ function readAuthPosture(runtime: CliCommandRuntime) {
|
|
|
76
77
|
});
|
|
77
78
|
const userStorePath = shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, 'auth-users.json');
|
|
78
79
|
const bootstrapCredentialPath = shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, 'auth-bootstrap.txt');
|
|
79
|
-
const
|
|
80
|
+
const operatorToken = readConnectedHostOperatorToken(runtime.homeDirectory);
|
|
80
81
|
return {
|
|
81
82
|
userStorePath,
|
|
82
83
|
userStorePresent: existsSync(userStorePath),
|
|
83
84
|
bootstrapCredentialPath,
|
|
84
85
|
bootstrapCredentialPresent: existsSync(bootstrapCredentialPath),
|
|
85
|
-
operatorTokenPath,
|
|
86
|
-
operatorTokenPresent:
|
|
86
|
+
operatorTokenPath: operatorToken.path,
|
|
87
|
+
operatorTokenPresent: operatorToken.present && Boolean(operatorToken.token),
|
|
87
88
|
};
|
|
88
89
|
}
|
|
89
90
|
|
package/src/cli/entrypoint.ts
CHANGED
|
@@ -186,6 +186,9 @@ export async function prepareShellCliRuntime(
|
|
|
186
186
|
configManager,
|
|
187
187
|
homeDirectory: bootstrapHomeDirectory,
|
|
188
188
|
});
|
|
189
|
+
const effectiveOperatorTokenPath = externalRuntime.operatorToken.present
|
|
190
|
+
? externalRuntime.operatorToken.path
|
|
191
|
+
: operatorTokenPath;
|
|
189
192
|
const statusOptions = {
|
|
190
193
|
configManager,
|
|
191
194
|
workingDirectory: bootstrapWorkingDir,
|
|
@@ -196,8 +199,8 @@ export async function prepareShellCliRuntime(
|
|
|
196
199
|
userStorePresent: existsSync(userStorePath),
|
|
197
200
|
bootstrapCredentialPath,
|
|
198
201
|
bootstrapCredentialPresent: existsSync(bootstrapCredentialPath),
|
|
199
|
-
operatorTokenPath,
|
|
200
|
-
operatorTokenPresent:
|
|
202
|
+
operatorTokenPath: effectiveOperatorTokenPath,
|
|
203
|
+
operatorTokenPresent: externalRuntime.operatorToken.present,
|
|
201
204
|
},
|
|
202
205
|
service,
|
|
203
206
|
externalRuntime,
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
1
|
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
4
2
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
5
3
|
import { SDK_VERSION } from '../version.ts';
|
|
4
|
+
import { readConnectedHostOperatorToken } from '../runtime/connected-host-auth.ts';
|
|
6
5
|
|
|
7
6
|
type JsonRecord = Record<string, unknown>;
|
|
8
7
|
|
|
@@ -47,18 +46,6 @@ function resolveBaseUrl(configManager: Pick<ConfigManager, 'get'>): string {
|
|
|
47
46
|
return `http://${host}:${Number.isFinite(port) ? port : 3421}`;
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
function readOperatorToken(homeDirectory: string): { readonly token: string | null; readonly path: string } {
|
|
51
|
-
const path = join(homeDirectory, '.goodvibes', 'daemon', 'operator-tokens.json');
|
|
52
|
-
if (!existsSync(path)) return { token: null, path };
|
|
53
|
-
try {
|
|
54
|
-
const parsed = JSON.parse(readFileSync(path, 'utf-8')) as unknown;
|
|
55
|
-
const token = isRecord(parsed) && typeof parsed.token === 'string' ? parsed.token : null;
|
|
56
|
-
return { token, path };
|
|
57
|
-
} catch {
|
|
58
|
-
return { token: null, path };
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
49
|
async function fetchJson(
|
|
63
50
|
url: string,
|
|
64
51
|
token: string | null,
|
|
@@ -90,7 +77,7 @@ export async function inspectCliExternalRuntime(
|
|
|
90
77
|
options: CliExternalRuntimeInspectionOptions,
|
|
91
78
|
): Promise<CliExternalRuntimeSnapshot> {
|
|
92
79
|
const baseUrl = resolveBaseUrl(options.configManager);
|
|
93
|
-
const token =
|
|
80
|
+
const token = readConnectedHostOperatorToken(options.homeDirectory);
|
|
94
81
|
const timeoutMs = options.timeoutMs ?? 1500;
|
|
95
82
|
const route = '/api/goodvibes-agent/knowledge/status' as const;
|
|
96
83
|
|
package/src/cli/management.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { formatProviderModel, getModelIdFromProviderModel } from '../config/prov
|
|
|
9
9
|
import { bootstrapRuntime } from '../runtime/bootstrap.ts';
|
|
10
10
|
import { createRuntimeServices } from '../runtime/services.ts';
|
|
11
11
|
import { createRuntimeStore } from '../runtime/store/index.ts';
|
|
12
|
+
import { readConnectedHostOperatorToken } from '../runtime/connected-host-auth.ts';
|
|
12
13
|
import type { RuntimeServices } from '../runtime/services.ts';
|
|
13
14
|
import { SecretsManager } from '../config/secrets.ts';
|
|
14
15
|
import { RuntimeEventBus, type TurnEvent } from '@/runtime/index.ts';
|
|
@@ -190,14 +191,14 @@ export function readAuthPaths(runtime: CliCommandRuntime) {
|
|
|
190
191
|
});
|
|
191
192
|
const userStorePath = shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, 'auth-users.json');
|
|
192
193
|
const bootstrapCredentialPath = shellPaths.resolveUserPath(GOODVIBES_AGENT_SURFACE_ROOT, 'auth-bootstrap.txt');
|
|
193
|
-
const
|
|
194
|
+
const operatorToken = readConnectedHostOperatorToken(runtime.homeDirectory);
|
|
194
195
|
return {
|
|
195
196
|
userStorePath,
|
|
196
197
|
userStorePresent: existsSync(userStorePath),
|
|
197
198
|
bootstrapCredentialPath,
|
|
198
199
|
bootstrapCredentialPresent: existsSync(bootstrapCredentialPath),
|
|
199
|
-
operatorTokenPath,
|
|
200
|
-
operatorTokenPresent:
|
|
200
|
+
operatorTokenPath: operatorToken.path,
|
|
201
|
+
operatorTokenPresent: operatorToken.present && Boolean(operatorToken.token),
|
|
201
202
|
};
|
|
202
203
|
}
|
|
203
204
|
|
|
@@ -21,7 +21,7 @@ export function registerGuidanceRuntimeCommands(registry: CommandRegistry): void
|
|
|
21
21
|
'Welcome To GoodVibes Agent',
|
|
22
22
|
' /setup - open Agent setup with current settings preloaded',
|
|
23
23
|
' /agent - open the Agent operator workspace',
|
|
24
|
-
' /knowledge - inspect isolated Agent Knowledge status, ask, and
|
|
24
|
+
' /knowledge - inspect isolated Agent Knowledge status, ask/search, libraries, map, connectors, and ingest paths',
|
|
25
25
|
' /memory - manage Agent-local memory',
|
|
26
26
|
' /personas - manage Agent-local personas',
|
|
27
27
|
' /skills - manage reusable Agent-local skills',
|
|
@@ -209,9 +209,9 @@ function renderKnowledgeAskResult(result: KnowledgeAskResult): string {
|
|
|
209
209
|
export const knowledgeCommand: SlashCommand = {
|
|
210
210
|
name: 'knowledge',
|
|
211
211
|
aliases: ['know', 'kb'],
|
|
212
|
-
description: 'Agent Knowledge: isolated Agent-owned
|
|
212
|
+
description: 'Agent Knowledge: isolated Agent-owned status, ask/search, source/node/issue lists, item lookup, map, connectors, ingest, and review queue.',
|
|
213
213
|
usage: '<subcommand> [args]',
|
|
214
|
-
argsHint: 'status|ask|ingest-url --yes|ingest-file --yes|import-bookmarks --yes|
|
|
214
|
+
argsHint: 'status|ask|search|list|get|map|connectors|connector|connector-doctor|ingest-url --yes|ingest-file --yes|import-urls --yes|import-bookmarks --yes|import-browser-history --yes|ingest-connector --yes|review-issue --yes|reindex --yes',
|
|
215
215
|
handler: async (args: string[], context: CommandContext): Promise<void> => {
|
|
216
216
|
if (args.length === 0 && context.openAgentWorkspace) {
|
|
217
217
|
context.openAgentWorkspace('knowledge');
|
package/src/runtime/bootstrap.ts
CHANGED
|
@@ -46,24 +46,16 @@ import { registerAgentHarnessTool } from '../tools/agent-harness-tool.ts';
|
|
|
46
46
|
|
|
47
47
|
const GOODVIBES_AGENT_OPERATOR_POLICY = [
|
|
48
48
|
'## GoodVibes Agent Operator Policy',
|
|
49
|
-
'-
|
|
50
|
-
'-
|
|
51
|
-
'-
|
|
52
|
-
'-
|
|
53
|
-
'-
|
|
54
|
-
'-
|
|
55
|
-
'-
|
|
56
|
-
'-
|
|
57
|
-
'-
|
|
58
|
-
'-
|
|
59
|
-
'- When the user explicitly asks Agent to send an alert, message, or notification to configured notification targets, use the `agent_notify` tool with confirm:true and the original user request. Do not infer external notifications from vague suggestions, and never create channel routes or account authorizations from the main conversation.',
|
|
60
|
-
'- When the user explicitly asks Agent to send one message to a specific configured channel, route, webhook, or link target, use the `agent_channel_send` tool with confirm:true and the original user request. It can deliver one message through configured delivery strategies, but must not create routes, authorize accounts, manage connected-host hosting, use default knowledge, use non-Agent knowledge spaces, create separate Agent jobs, or request GoodVibes TUI delegation.',
|
|
61
|
-
'- When the user explicitly asks for a reminder or asks Agent to schedule a reminder, use the `agent_reminder_schedule` tool with confirm:true and the original user request. That creates one connected schedules.create reminder on the external GoodVibes host. Do not infer reminders from vague suggestions or routine startup, and never create local scheduler jobs.',
|
|
62
|
-
'- GoodVibes TUI delegation is never the default Agent reasoning path. Do not delegate planning, research, operations, knowledge, memory, configuration, approvals, automation observability, or ordinary assistant work.',
|
|
63
|
-
'- GoodVibes Agent is not the coding TUI. Do not use the `agent` tool to create coding-role Agent jobs or batch job roots from Agent.',
|
|
64
|
-
'- When the user explicitly asks to build, implement, fix, patch, or review code, preserve the full original user ask and delegate one build request to GoodVibes TUI through the public shared-session/build-delegation contract. Include clear executionIntent and request delegated review only for explicit build/fix/review work or when the user explicitly asks for delegated Agent review.',
|
|
65
|
-
'- Do not narrow explicit build/fix/review requests into design-only, read-only, or no-write work unless the user explicitly requested that limitation. TUI owns file edits, git/worktree work, execution isolation UX, and delegated review coordination.',
|
|
66
|
-
'- If a stable public delegation route is unavailable, say that the task needs GoodVibes TUI delegation and report the missing route instead of pretending to implement it locally or creating sibling Agent jobs.',
|
|
49
|
+
'- Work serially in the main conversation by default: answer, inspect, summarize, remember useful non-secret facts, configure Agent-local state, and use safe read-only connected-host/operator routes.',
|
|
50
|
+
'- Connected-host lifecycle is external. Do not start, stop, restart, install, expose, or mutate host listeners/network posture from Agent.',
|
|
51
|
+
'- Read tools: `agent_operator_briefing` for connected work/approvals/automation/schedules, `agent_knowledge` for isolated Agent Knowledge, `agent_harness` for harness catalogs/settings/status.',
|
|
52
|
+
'- State tools: `agent_work_plan` for visible local work items; `agent_local_registry` for Agent-local notes, memory, personas, skills, bundles, and routines. Keep records non-secret, sourced, and reviewable.',
|
|
53
|
+
'- Confirmed tools: use `agent_operator_action`, `agent_knowledge_ingest`, `agent_media_generate`, `agent_notify`, `agent_channel_send`, and `agent_reminder_schedule` only for explicit user requests with confirm:true and explicitUserRequest.',
|
|
54
|
+
'- Agent Knowledge must use only `/api/goodvibes-agent/knowledge/*` and fail closed. Do not use default knowledge or non-Agent knowledge spaces.',
|
|
55
|
+
'- External delivery, media generation, reminders, settings writes, slash-command mirrors, workspace action mirrors, and destructive local changes require explicit user intent and the owning tool/command confirmation.',
|
|
56
|
+
'- Routines run in this serial conversation unless explicitly promoted to a connected schedule. Do not create hidden Agent jobs or local scheduler jobs.',
|
|
57
|
+
'- Do not delegate planning, research, operations, knowledge, memory, configuration, approvals, observability, or ordinary assistant work.',
|
|
58
|
+
'- For explicit build, implement, fix, patch, or review requests, preserve the full original ask and use the public shared-session/build-delegation route. If that route is unavailable, report the missing route instead of pretending to perform the work locally.',
|
|
67
59
|
].join('\n');
|
|
68
60
|
|
|
69
61
|
function joinPromptParts(...parts: Array<string | null | undefined>): string {
|
|
@@ -20,6 +20,22 @@ export function connectedHostOperatorTokenPath(homeDirectory: string): string {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export function readConnectedHostOperatorToken(homeDirectory: string): ConnectedHostOperatorToken {
|
|
23
|
+
const connectedHostEnvToken = process.env.GOODVIBES_CONNECTED_HOST_TOKEN?.trim();
|
|
24
|
+
if (connectedHostEnvToken) {
|
|
25
|
+
return {
|
|
26
|
+
path: 'env:GOODVIBES_CONNECTED_HOST_TOKEN',
|
|
27
|
+
present: true,
|
|
28
|
+
token: connectedHostEnvToken,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const legacyEnvToken = process.env.GOODVIBES_DAEMON_TOKEN?.trim();
|
|
32
|
+
if (legacyEnvToken) {
|
|
33
|
+
return {
|
|
34
|
+
path: 'env:GOODVIBES_DAEMON_TOKEN',
|
|
35
|
+
present: true,
|
|
36
|
+
token: legacyEnvToken,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
23
39
|
const path = connectedHostOperatorTokenPath(homeDirectory);
|
|
24
40
|
if (!existsSync(path)) return { path, present: false, token: null };
|
|
25
41
|
try {
|
|
@@ -82,11 +82,7 @@ export function validateRegistryToolInvocationForAgentPolicy(args: RegistryToolA
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
function narrowAnalyzeToolDefinitionForAgentPolicy(tool: Tool): void {
|
|
85
|
-
tool.definition.description =
|
|
86
|
-
'Run local, static project analysis for GoodVibes Agent.',
|
|
87
|
-
'npm registry upgrade checks and hidden secondary LLM diff analysis are disabled in the main conversation.',
|
|
88
|
-
'Delegate package-upgrade and review workflows to GoodVibes TUI when they become build/fix/review work.',
|
|
89
|
-
].join(' ');
|
|
85
|
+
tool.definition.description = 'Run local, static project analysis for GoodVibes Agent.';
|
|
90
86
|
tool.definition.sideEffects = ['read_fs'];
|
|
91
87
|
|
|
92
88
|
const properties = tool.definition.parameters.properties;
|
|
@@ -101,10 +97,7 @@ function narrowAnalyzeToolDefinitionForAgentPolicy(tool: Tool): void {
|
|
|
101
97
|
}
|
|
102
98
|
|
|
103
99
|
function narrowRegistryToolDefinitionForAgentPolicy(tool: Tool): void {
|
|
104
|
-
tool.definition.description =
|
|
105
|
-
'Discover and preview GoodVibes Agent skills, agents, and tools.',
|
|
106
|
-
'Full content materialization and arbitrary .goodvibes file reads are disabled in the main conversation.',
|
|
107
|
-
].join(' ');
|
|
100
|
+
tool.definition.description = 'Discover and preview GoodVibes Agent registry entries.';
|
|
108
101
|
tool.definition.sideEffects = ['read_fs'];
|
|
109
102
|
|
|
110
103
|
const properties = tool.definition.parameters.properties;
|
|
@@ -41,13 +41,7 @@ export function createAgentChannelSendTool(
|
|
|
41
41
|
return {
|
|
42
42
|
definition: {
|
|
43
43
|
name: 'agent_channel_send',
|
|
44
|
-
description:
|
|
45
|
-
'Send one explicitly confirmed message through a configured GoodVibes Agent delivery target from the main conversation.',
|
|
46
|
-
'Use only when the user explicitly asks Agent to send, message, alert, or notify a channel target.',
|
|
47
|
-
'Exactly one target must be supplied: channel, route, webhook, or link.',
|
|
48
|
-
'This tool does not create channel routes, authorize accounts, manage connected-host hosting, use default knowledge, use non-Agent knowledge segments, create separate Agent jobs, run delegated review, or invoke arbitrary routes.',
|
|
49
|
-
'Set confirm:true only for an explicit user request. Otherwise return the preview/confirmation error.',
|
|
50
|
-
].join(' '),
|
|
44
|
+
description: 'Send one confirmed message through one configured Agent target.',
|
|
51
45
|
parameters: {
|
|
52
46
|
type: 'object',
|
|
53
47
|
properties: {
|
|
@@ -61,7 +55,7 @@ export function createAgentChannelSendTool(
|
|
|
61
55
|
},
|
|
62
56
|
channel: {
|
|
63
57
|
type: 'string',
|
|
64
|
-
description: 'Optional channel target
|
|
58
|
+
description: 'Optional channel target. Use exactly one target field.',
|
|
65
59
|
},
|
|
66
60
|
route: {
|
|
67
61
|
type: 'string',
|
|
@@ -77,7 +71,7 @@ export function createAgentChannelSendTool(
|
|
|
77
71
|
},
|
|
78
72
|
confirm: {
|
|
79
73
|
type: 'boolean',
|
|
80
|
-
description: 'Required true
|
|
74
|
+
description: 'Required true for confirmed delivery.',
|
|
81
75
|
},
|
|
82
76
|
explicitUserRequest: {
|
|
83
77
|
type: 'string',
|
|
@@ -7,11 +7,7 @@ const CONTEXT_TOOL_DENIAL = [
|
|
|
7
7
|
].join(' ');
|
|
8
8
|
|
|
9
9
|
export function wrapBlockedContextToolForAgentPolicy(tool: Tool): void {
|
|
10
|
-
tool.definition.description =
|
|
11
|
-
'Blocked in GoodVibes Agent main conversation: non-Agent runtime context.',
|
|
12
|
-
'Use explicit Agent CLI/slash status, compat, setup, and Agent Knowledge commands for product-scoped context.',
|
|
13
|
-
'Default knowledge, non-Agent knowledge segments, and non-Agent runtime assumptions are not Agent fallbacks.',
|
|
14
|
-
].join(' ');
|
|
10
|
+
tool.definition.description = 'Blocked in GoodVibes Agent: non-Agent runtime context.';
|
|
15
11
|
tool.definition.sideEffects = [];
|
|
16
12
|
tool.definition.parameters = {
|
|
17
13
|
type: 'object',
|
|
@@ -82,10 +82,7 @@ export function normalizeFindToolInvocationForAgentPolicy(args: FindToolArgs): F
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
function narrowFindToolDefinitionForAgentPolicy(tool: Tool): void {
|
|
85
|
-
tool.definition.description =
|
|
86
|
-
'Search the project for GoodVibes Agent using serial, gitignore-respecting read-only queries.',
|
|
87
|
-
'Hidden-file scans, symlink traversal, gitignore bypass, broad previews, full symbol dumps, and parallel search are disabled in the main conversation.',
|
|
88
|
-
].join(' ');
|
|
85
|
+
tool.definition.description = 'Search project files with serial, gitignore-respecting read-only queries.';
|
|
89
86
|
tool.definition.sideEffects = ['read_fs'];
|
|
90
87
|
tool.definition.concurrency = 'serial';
|
|
91
88
|
|