@pellux/goodvibes-agent 1.0.1 → 1.0.3
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 +14 -0
- package/README.md +8 -4
- package/dist/package/main.js +14321 -12304
- package/docs/README.md +4 -2
- package/docs/channels-remote-and-api.md +4 -0
- package/docs/connected-host.md +2 -0
- package/docs/getting-started.md +6 -2
- package/docs/knowledge-artifacts-and-multimodal.md +5 -3
- package/docs/project-planning.md +3 -1
- package/docs/providers-and-routing.md +3 -0
- package/docs/release-and-publishing.md +7 -6
- package/docs/tools-and-commands.md +101 -2
- package/docs/voice-and-live-tts.md +2 -0
- package/package.json +1 -1
- package/src/agent/harness-control.ts +266 -0
- package/src/cli/help.ts +26 -0
- package/src/config/agent-settings-policy.ts +44 -0
- package/src/input/agent-workspace-activation.ts +14 -6
- package/src/input/commands/operator-runtime.ts +139 -3
- package/src/input/settings-modal-agent-policy.ts +5 -44
- package/src/runtime/bootstrap.ts +3 -0
- package/src/tools/agent-harness-cli-metadata.ts +152 -0
- package/src/tools/agent-harness-local-operations.ts +233 -0
- package/src/tools/agent-harness-metadata.ts +408 -0
- package/src/tools/agent-harness-model-tool-catalog.ts +36 -0
- package/src/tools/agent-harness-panel-metadata.ts +121 -0
- package/src/tools/agent-harness-tool.ts +798 -0
- package/src/tools/agent-local-registry-requirements.ts +18 -0
- package/src/tools/agent-local-registry-tool.ts +88 -34
- package/src/version.ts +1 -1
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AgentSkillRequirement } from '../agent/skill-registry.ts';
|
|
2
|
+
|
|
3
|
+
function readList(value: unknown): readonly string[] {
|
|
4
|
+
if (typeof value === 'string') return value.split(',').map((entry) => entry.trim()).filter(Boolean);
|
|
5
|
+
if (!Array.isArray(value)) return [];
|
|
6
|
+
return value.filter((entry): entry is string => typeof entry === 'string').map((entry) => entry.trim()).filter(Boolean);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function buildAgentLocalRequirements(
|
|
10
|
+
requiresEnv: unknown,
|
|
11
|
+
requiresCommands: unknown,
|
|
12
|
+
): readonly AgentSkillRequirement[] | undefined {
|
|
13
|
+
if (requiresEnv === undefined && requiresCommands === undefined) return undefined;
|
|
14
|
+
return [
|
|
15
|
+
...readList(requiresEnv).map((name) => ({ kind: 'env' as const, name })),
|
|
16
|
+
...readList(requiresCommands).map((name) => ({ kind: 'command' as const, name })),
|
|
17
|
+
];
|
|
18
|
+
}
|
|
@@ -1,33 +1,17 @@
|
|
|
1
1
|
import type { Tool } from '@pellux/goodvibes-sdk/platform/types';
|
|
2
2
|
import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
|
|
3
3
|
import type { ShellPathService } from '@/runtime/index.ts';
|
|
4
|
-
import {
|
|
5
|
-
MemoryRegistry,
|
|
6
|
-
type MemoryClass,
|
|
7
|
-
type MemoryRecord,
|
|
8
|
-
type MemoryScope,
|
|
9
|
-
} from '@pellux/goodvibes-sdk/platform/state';
|
|
4
|
+
import { MemoryRegistry, type MemoryClass, type MemoryRecord, type MemoryScope } from '@pellux/goodvibes-sdk/platform/state';
|
|
10
5
|
import { AgentPersonaRegistry, type AgentPersonaRecord } from '../agent/persona-registry.ts';
|
|
11
6
|
import { AgentNoteRegistry, type AgentNoteRecord } from '../agent/note-registry.ts';
|
|
12
7
|
import { AgentRoutineRegistry, type AgentRoutineRecord } from '../agent/routine-registry.ts';
|
|
13
8
|
import { AgentSkillRegistry, type AgentSkillBundleRecord, type AgentSkillRecord } from '../agent/skill-registry.ts';
|
|
14
9
|
import { assertNoSecretLikeMemoryText } from '../agent/memory-safety.ts';
|
|
15
10
|
import { formatAgentRecordOrigin, formatAgentRecordReference, formatAgentRecordReviewState } from '../agent/record-labels.ts';
|
|
11
|
+
import { buildAgentLocalRequirements } from './agent-local-registry-requirements.ts';
|
|
16
12
|
|
|
17
13
|
export type AgentLocalRegistryDomain = 'memory' | 'note' | 'persona' | 'skill' | 'skill_bundle' | 'routine';
|
|
18
|
-
export type AgentLocalRegistryAction =
|
|
19
|
-
| 'list'
|
|
20
|
-
| 'search'
|
|
21
|
-
| 'get'
|
|
22
|
-
| 'create'
|
|
23
|
-
| 'update'
|
|
24
|
-
| 'enable'
|
|
25
|
-
| 'disable'
|
|
26
|
-
| 'review'
|
|
27
|
-
| 'stale'
|
|
28
|
-
| 'use'
|
|
29
|
-
| 'clear_active'
|
|
30
|
-
| 'start';
|
|
14
|
+
export type AgentLocalRegistryAction = 'list' | 'search' | 'get' | 'create' | 'update' | 'enable' | 'disable' | 'review' | 'stale' | 'use' | 'clear_active' | 'start' | 'delete';
|
|
31
15
|
|
|
32
16
|
export interface AgentLocalRegistryToolArgs {
|
|
33
17
|
readonly domain?: unknown;
|
|
@@ -48,28 +32,20 @@ export interface AgentLocalRegistryToolArgs {
|
|
|
48
32
|
readonly steps?: unknown;
|
|
49
33
|
readonly skills?: unknown;
|
|
50
34
|
readonly skillIds?: unknown;
|
|
35
|
+
readonly requiresEnv?: unknown;
|
|
36
|
+
readonly requiresCommands?: unknown;
|
|
51
37
|
readonly triggers?: unknown;
|
|
52
38
|
readonly tags?: unknown;
|
|
53
39
|
readonly reason?: unknown;
|
|
54
40
|
readonly enabled?: unknown;
|
|
41
|
+
readonly activate?: unknown;
|
|
55
42
|
readonly provenance?: unknown;
|
|
43
|
+
readonly confirm?: unknown;
|
|
44
|
+
readonly explicitUserRequest?: unknown;
|
|
56
45
|
}
|
|
57
46
|
|
|
58
47
|
const DOMAINS: readonly AgentLocalRegistryDomain[] = ['memory', 'note', 'persona', 'skill', 'skill_bundle', 'routine'];
|
|
59
|
-
const ACTIONS: readonly AgentLocalRegistryAction[] = [
|
|
60
|
-
'list',
|
|
61
|
-
'search',
|
|
62
|
-
'get',
|
|
63
|
-
'create',
|
|
64
|
-
'update',
|
|
65
|
-
'enable',
|
|
66
|
-
'disable',
|
|
67
|
-
'review',
|
|
68
|
-
'stale',
|
|
69
|
-
'use',
|
|
70
|
-
'clear_active',
|
|
71
|
-
'start',
|
|
72
|
-
];
|
|
48
|
+
const ACTIONS: readonly AgentLocalRegistryAction[] = ['list', 'search', 'get', 'create', 'update', 'enable', 'disable', 'review', 'stale', 'use', 'clear_active', 'start', 'delete'];
|
|
73
49
|
const MEMORY_CLASSES: readonly MemoryClass[] = ['decision', 'constraint', 'incident', 'pattern', 'fact', 'risk', 'runbook', 'architecture', 'ownership'];
|
|
74
50
|
const MEMORY_SCOPES: readonly MemoryScope[] = ['session', 'project', 'team'];
|
|
75
51
|
const AGENT_TOOL_PROVENANCE = 'agent-local-registry-tool';
|
|
@@ -86,6 +62,10 @@ function readString(value: unknown): string {
|
|
|
86
62
|
return typeof value === 'string' ? value.trim() : '';
|
|
87
63
|
}
|
|
88
64
|
|
|
65
|
+
function readAffirmative(value: unknown): boolean {
|
|
66
|
+
const normalized = readString(value).toLowerCase(); return value === true || (typeof value === 'string' && (normalized === '' || normalized === 'yes' || normalized === 'y' || normalized === 'true' || normalized === 'on'));
|
|
67
|
+
}
|
|
68
|
+
|
|
89
69
|
function readStringList(value: unknown): readonly string[] {
|
|
90
70
|
if (typeof value === 'string') {
|
|
91
71
|
return value.split(',').map((entry) => entry.trim()).filter(Boolean);
|
|
@@ -130,6 +110,12 @@ function requireId(args: AgentLocalRegistryToolArgs): string {
|
|
|
130
110
|
return id;
|
|
131
111
|
}
|
|
132
112
|
|
|
113
|
+
function requireConfirmedDelete(args: AgentLocalRegistryToolArgs, label: string): void {
|
|
114
|
+
const explicitUserRequest = readString(args.explicitUserRequest);
|
|
115
|
+
if (!explicitUserRequest) throw new Error(`${label} deletion requires explicitUserRequest with the user's exact request or a short faithful summary.`);
|
|
116
|
+
if (args.confirm !== true) throw new Error(`${label} deletion requires confirm:true after an explicit user request.`);
|
|
117
|
+
}
|
|
118
|
+
|
|
133
119
|
function requireName(args: AgentLocalRegistryToolArgs): string {
|
|
134
120
|
const name = readString(args.name);
|
|
135
121
|
if (!name) throw new Error('name is required.');
|
|
@@ -202,6 +188,7 @@ async function handleMemory(registry: MemoryRegistry, action: AgentLocalRegistry
|
|
|
202
188
|
const summary = requireSummary(args);
|
|
203
189
|
const detail = readString(args.detail || args.body);
|
|
204
190
|
const tags = readStringList(args.tags);
|
|
191
|
+
const confidence = readOptionalConfidence(args.confidence);
|
|
205
192
|
assertNoSecretLikeMemoryText([summary, detail, ...tags]);
|
|
206
193
|
const record = await registry.add({
|
|
207
194
|
scope: readMemoryScope(args),
|
|
@@ -209,6 +196,7 @@ async function handleMemory(registry: MemoryRegistry, action: AgentLocalRegistry
|
|
|
209
196
|
summary,
|
|
210
197
|
detail,
|
|
211
198
|
tags: [...tags],
|
|
199
|
+
...(confidence === undefined ? {} : { review: { state: 'fresh' as const, confidence } }),
|
|
212
200
|
provenance: [{ kind: 'event', ref: readString(args.provenance) || AGENT_TOOL_PROVENANCE }],
|
|
213
201
|
});
|
|
214
202
|
return [
|
|
@@ -258,6 +246,15 @@ async function handleMemory(registry: MemoryRegistry, action: AgentLocalRegistry
|
|
|
258
246
|
` id ${record.id}`,
|
|
259
247
|
].join('\n');
|
|
260
248
|
}
|
|
249
|
+
if (action === 'delete') {
|
|
250
|
+
const id = requireId(args);
|
|
251
|
+
requireConfirmedDelete(args, 'Agent-local memory');
|
|
252
|
+
if (!registry.delete(id)) return `Unknown Agent-local memory ${id}`;
|
|
253
|
+
return [
|
|
254
|
+
'Deleted Agent-local memory',
|
|
255
|
+
` id ${id}`,
|
|
256
|
+
].join('\n');
|
|
257
|
+
}
|
|
261
258
|
throw new Error(`Action ${action} is not valid for memory.`);
|
|
262
259
|
}
|
|
263
260
|
|
|
@@ -332,6 +329,15 @@ function handleNote(shellPaths: ShellPathService, action: AgentLocalRegistryActi
|
|
|
332
329
|
` id ${note.id}`,
|
|
333
330
|
].join('\n');
|
|
334
331
|
}
|
|
332
|
+
if (action === 'delete') {
|
|
333
|
+
requireConfirmedDelete(args, 'Agent-local note');
|
|
334
|
+
const note = registry.deleteNote(requireId(args));
|
|
335
|
+
return [
|
|
336
|
+
'Deleted Agent-local note',
|
|
337
|
+
` id ${note.id}`,
|
|
338
|
+
` title ${note.title}`,
|
|
339
|
+
].join('\n');
|
|
340
|
+
}
|
|
335
341
|
throw new Error(`Action ${action} is not valid for notes.`);
|
|
336
342
|
}
|
|
337
343
|
|
|
@@ -406,6 +412,7 @@ function handlePersona(shellPaths: ShellPathService, action: AgentLocalRegistryA
|
|
|
406
412
|
source: 'agent',
|
|
407
413
|
provenance: readString(args.provenance) || AGENT_TOOL_PROVENANCE,
|
|
408
414
|
});
|
|
415
|
+
if (args.activate !== undefined && readAffirmative(args.activate)) registry.setActive(persona.id);
|
|
409
416
|
return [
|
|
410
417
|
'Created Agent-local persona',
|
|
411
418
|
` id ${persona.id}`,
|
|
@@ -413,6 +420,7 @@ function handlePersona(shellPaths: ShellPathService, action: AgentLocalRegistryA
|
|
|
413
420
|
].join('\n');
|
|
414
421
|
}
|
|
415
422
|
if (action === 'update') {
|
|
423
|
+
const wasActive = registry.snapshot().activePersonaId === requireId(args);
|
|
416
424
|
const persona = registry.update(requireId(args), {
|
|
417
425
|
name: readString(args.name) || undefined,
|
|
418
426
|
description: readString(args.description) || undefined,
|
|
@@ -421,6 +429,7 @@ function handlePersona(shellPaths: ShellPathService, action: AgentLocalRegistryA
|
|
|
421
429
|
triggers: args.triggers === undefined ? undefined : readStringList(args.triggers),
|
|
422
430
|
provenance: readString(args.provenance) || AGENT_TOOL_PROVENANCE,
|
|
423
431
|
});
|
|
432
|
+
if (args.activate !== undefined) { if (readAffirmative(args.activate)) registry.setActive(persona.id); else if (wasActive) registry.clearActive(); }
|
|
424
433
|
return [
|
|
425
434
|
'Updated Agent-local persona',
|
|
426
435
|
` id ${persona.id}`,
|
|
@@ -453,6 +462,15 @@ function handlePersona(shellPaths: ShellPathService, action: AgentLocalRegistryA
|
|
|
453
462
|
` id ${persona.id}`,
|
|
454
463
|
].join('\n');
|
|
455
464
|
}
|
|
465
|
+
if (action === 'delete') {
|
|
466
|
+
requireConfirmedDelete(args, 'Agent-local persona');
|
|
467
|
+
const persona = registry.deletePersona(requireId(args));
|
|
468
|
+
return [
|
|
469
|
+
'Deleted Agent-local persona',
|
|
470
|
+
` id ${persona.id}`,
|
|
471
|
+
` name ${persona.name}`,
|
|
472
|
+
].join('\n');
|
|
473
|
+
}
|
|
456
474
|
throw new Error(`Action ${action} is not valid for personas.`);
|
|
457
475
|
}
|
|
458
476
|
|
|
@@ -480,6 +498,7 @@ function handleSkill(shellPaths: ShellPathService, action: AgentLocalRegistryAct
|
|
|
480
498
|
procedure: requireTextField(args.procedure, 'procedure'),
|
|
481
499
|
triggers: readStringList(args.triggers),
|
|
482
500
|
tags: readStringList(args.tags),
|
|
501
|
+
requirements: buildAgentLocalRequirements(args.requiresEnv, args.requiresCommands),
|
|
483
502
|
enabled: args.enabled === true,
|
|
484
503
|
source: 'agent',
|
|
485
504
|
provenance: readString(args.provenance) || AGENT_TOOL_PROVENANCE,
|
|
@@ -497,6 +516,7 @@ function handleSkill(shellPaths: ShellPathService, action: AgentLocalRegistryAct
|
|
|
497
516
|
procedure: readString(args.procedure) || undefined,
|
|
498
517
|
triggers: args.triggers === undefined ? undefined : readStringList(args.triggers),
|
|
499
518
|
tags: args.tags === undefined ? undefined : readStringList(args.tags),
|
|
519
|
+
requirements: buildAgentLocalRequirements(args.requiresEnv, args.requiresCommands),
|
|
500
520
|
provenance: readString(args.provenance) || AGENT_TOOL_PROVENANCE,
|
|
501
521
|
});
|
|
502
522
|
return [
|
|
@@ -527,6 +547,15 @@ function handleSkill(shellPaths: ShellPathService, action: AgentLocalRegistryAct
|
|
|
527
547
|
` id ${skill.id}`,
|
|
528
548
|
].join('\n');
|
|
529
549
|
}
|
|
550
|
+
if (action === 'delete') {
|
|
551
|
+
requireConfirmedDelete(args, 'Agent-local skill');
|
|
552
|
+
const skill = registry.deleteSkill(requireId(args));
|
|
553
|
+
return [
|
|
554
|
+
'Deleted Agent-local skill',
|
|
555
|
+
` id ${skill.id}`,
|
|
556
|
+
` name ${skill.name}`,
|
|
557
|
+
].join('\n');
|
|
558
|
+
}
|
|
530
559
|
throw new Error(`Action ${action} is not valid for skills.`);
|
|
531
560
|
}
|
|
532
561
|
|
|
@@ -595,6 +624,15 @@ function handleSkillBundle(shellPaths: ShellPathService, action: AgentLocalRegis
|
|
|
595
624
|
` id ${bundle.id}`,
|
|
596
625
|
].join('\n');
|
|
597
626
|
}
|
|
627
|
+
if (action === 'delete') {
|
|
628
|
+
requireConfirmedDelete(args, 'Agent-local skill bundle');
|
|
629
|
+
const bundle = registry.deleteBundle(requireId(args));
|
|
630
|
+
return [
|
|
631
|
+
'Deleted Agent-local skill bundle',
|
|
632
|
+
` id ${bundle.id}`,
|
|
633
|
+
` name ${bundle.name}`,
|
|
634
|
+
].join('\n');
|
|
635
|
+
}
|
|
598
636
|
throw new Error(`Action ${action} is not valid for skill bundles.`);
|
|
599
637
|
}
|
|
600
638
|
|
|
@@ -621,6 +659,7 @@ function handleRoutine(shellPaths: ShellPathService, action: AgentLocalRegistryA
|
|
|
621
659
|
steps: requireTextField(args.steps, 'steps'),
|
|
622
660
|
triggers: readStringList(args.triggers),
|
|
623
661
|
tags: readStringList(args.tags),
|
|
662
|
+
requirements: buildAgentLocalRequirements(args.requiresEnv, args.requiresCommands),
|
|
624
663
|
enabled: args.enabled === true,
|
|
625
664
|
source: 'agent',
|
|
626
665
|
provenance: readString(args.provenance) || AGENT_TOOL_PROVENANCE,
|
|
@@ -638,6 +677,7 @@ function handleRoutine(shellPaths: ShellPathService, action: AgentLocalRegistryA
|
|
|
638
677
|
steps: readString(args.steps) || undefined,
|
|
639
678
|
triggers: args.triggers === undefined ? undefined : readStringList(args.triggers),
|
|
640
679
|
tags: args.tags === undefined ? undefined : readStringList(args.tags),
|
|
680
|
+
requirements: buildAgentLocalRequirements(args.requiresEnv, args.requiresCommands),
|
|
641
681
|
provenance: readString(args.provenance) || AGENT_TOOL_PROVENANCE,
|
|
642
682
|
});
|
|
643
683
|
return [
|
|
@@ -679,6 +719,15 @@ function handleRoutine(shellPaths: ShellPathService, action: AgentLocalRegistryA
|
|
|
679
719
|
` id ${routine.id}`,
|
|
680
720
|
].join('\n');
|
|
681
721
|
}
|
|
722
|
+
if (action === 'delete') {
|
|
723
|
+
requireConfirmedDelete(args, 'Agent-local routine');
|
|
724
|
+
const routine = registry.deleteRoutine(requireId(args));
|
|
725
|
+
return [
|
|
726
|
+
'Deleted Agent-local routine',
|
|
727
|
+
` id ${routine.id}`,
|
|
728
|
+
` name ${routine.name}`,
|
|
729
|
+
].join('\n');
|
|
730
|
+
}
|
|
682
731
|
throw new Error(`Action ${action} is not valid for routines.`);
|
|
683
732
|
}
|
|
684
733
|
|
|
@@ -689,7 +738,7 @@ export function createAgentLocalRegistryTool(shellPaths: ShellPathService, memor
|
|
|
689
738
|
description: [
|
|
690
739
|
'Inspect and maintain GoodVibes Agent-local notes, memory, personas, skills, and routines from the main conversation.',
|
|
691
740
|
'Use this for safe self-improvement: capture scratchpad notes, remember durable non-secret facts, create or refine reusable behavior, bundle related skills, enable skills/routines, choose personas, review/stale records, and start routines in the same serial conversation.',
|
|
692
|
-
'This tool cannot
|
|
741
|
+
'Destructive record deletion requires confirm:true plus explicitUserRequest. This tool cannot create schedules, mutate connected hosts, send messages, run background jobs, or delegate build work.',
|
|
693
742
|
].join(' '),
|
|
694
743
|
parameters: {
|
|
695
744
|
type: 'object',
|
|
@@ -712,11 +761,16 @@ export function createAgentLocalRegistryTool(shellPaths: ShellPathService, memor
|
|
|
712
761
|
steps: { type: 'string', description: 'Routine steps.' },
|
|
713
762
|
skills: { type: 'array', items: { type: 'string' }, description: 'Skill ids for skill_bundle create/update.' },
|
|
714
763
|
skillIds: { type: 'array', items: { type: 'string' }, description: 'Skill ids for skill_bundle create/update.' },
|
|
764
|
+
requiresEnv: { type: 'array', items: { type: 'string' }, description: 'Environment variable names required by a skill or routine. Values are never stored.' },
|
|
765
|
+
requiresCommands: { type: 'array', items: { type: 'string' }, description: 'Command names required by a skill or routine.' },
|
|
715
766
|
triggers: { type: 'array', items: { type: 'string' } },
|
|
716
767
|
tags: { type: 'array', items: { type: 'string' } },
|
|
717
768
|
reason: { type: 'string' },
|
|
718
769
|
enabled: { type: 'boolean' },
|
|
770
|
+
activate: { type: 'boolean', description: 'Activate a created/updated persona, or clear it when updating the active persona with false.' },
|
|
719
771
|
provenance: { type: 'string' },
|
|
772
|
+
confirm: { type: 'boolean', description: 'Required true for delete after an explicit user request.' },
|
|
773
|
+
explicitUserRequest: { type: 'string', description: 'Exact user request or faithful short summary authorizing delete.' },
|
|
720
774
|
},
|
|
721
775
|
required: ['domain', 'action'],
|
|
722
776
|
additionalProperties: false,
|
package/src/version.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { join } from 'node:path';
|
|
|
6
6
|
// The prebuild script updates the fallback value before compilation.
|
|
7
7
|
// Uses import.meta.dir (Bun) to locate package.json relative to this file,
|
|
8
8
|
// which is correct regardless of the process working directory.
|
|
9
|
-
let _version = '1.0.
|
|
9
|
+
let _version = '1.0.3';
|
|
10
10
|
let _sdkVersion = '0.33.35';
|
|
11
11
|
try {
|
|
12
12
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8')) as {
|