@pellux/goodvibes-agent 1.1.6 → 1.1.7
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 +6 -0
- package/dist/package/main.js +261 -92
- package/package.json +1 -1
- package/src/runtime/bootstrap-core.ts +4 -0
- package/src/runtime/tool-permission-safety.ts +93 -0
- package/src/tools/agent-context-policy.ts +137 -10
- package/src/tools/agent-tool-policy-guard.ts +4 -4
- package/src/tools/tool-execution-safety.ts +41 -0
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Product-facing release notes for GoodVibes Agent.
|
|
4
4
|
|
|
5
|
+
## 1.1.7 - 2026-06-05
|
|
6
|
+
|
|
7
|
+
- Hardened the Agent model tool surface so goodvibes_context routes to the Agent harness instead of dead-ending.
|
|
8
|
+
- Added tool execution and permission safety guards so registered model tools return structured failures instead of aborting turns.
|
|
9
|
+
- Added registered-tool smoke coverage for the Agent-guarded platform tool roster.
|
|
10
|
+
|
|
5
11
|
## 1.1.6 - 2026-06-05
|
|
6
12
|
|
|
7
13
|
- Fixed Import GoodVibes settings so it also imports active and pending provider subscriptions from the GoodVibes TUI user store into Agent-owned subscription state.
|
package/dist/package/main.js
CHANGED
|
@@ -450372,23 +450372,6 @@ function createSchema2(db) {
|
|
|
450372
450372
|
`);
|
|
450373
450373
|
db.run(`CREATE INDEX IF NOT EXISTS idx_knowledge_schedules_job_id ON knowledge_schedules(job_id)`);
|
|
450374
450374
|
}
|
|
450375
|
-
function getKnowledgeSchemaStatements() {
|
|
450376
|
-
const statements = [];
|
|
450377
|
-
createSchema2({
|
|
450378
|
-
run(sql) {
|
|
450379
|
-
const normalized = sql.trim();
|
|
450380
|
-
if (normalized.length > 0)
|
|
450381
|
-
statements.push(normalized);
|
|
450382
|
-
}
|
|
450383
|
-
});
|
|
450384
|
-
return statements;
|
|
450385
|
-
}
|
|
450386
|
-
function renderKnowledgeSchemaSql() {
|
|
450387
|
-
return `${getKnowledgeSchemaStatements().map((statement) => statement.endsWith(";") ? statement : `${statement};`).join(`
|
|
450388
|
-
|
|
450389
|
-
`)}
|
|
450390
|
-
`;
|
|
450391
|
-
}
|
|
450392
450375
|
function rowObject(columns, values2) {
|
|
450393
450376
|
return Object.fromEntries(columns.map((column, index) => [column, values2[index]]));
|
|
450394
450377
|
}
|
|
@@ -763671,9 +763654,6 @@ var init_ingest = __esm(() => {
|
|
|
763671
763654
|
// node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/browser-history/index.js
|
|
763672
763655
|
var init_browser_history = __esm(() => {
|
|
763673
763656
|
init_ingest();
|
|
763674
|
-
init_discover();
|
|
763675
|
-
init_readers();
|
|
763676
|
-
init_paths2();
|
|
763677
763657
|
});
|
|
763678
763658
|
|
|
763679
763659
|
// node_modules/graphql/jsutils/devAssert.mjs
|
|
@@ -781313,7 +781293,6 @@ var init_semantic = __esm(() => {
|
|
|
781313
781293
|
init_llm();
|
|
781314
781294
|
init_gap_repair();
|
|
781315
781295
|
init_service4();
|
|
781316
|
-
init_self_improvement();
|
|
781317
781296
|
});
|
|
781318
781297
|
|
|
781319
781298
|
// node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/home-graph/helpers.js
|
|
@@ -785282,40 +785261,8 @@ var init_map_view = __esm(() => {
|
|
|
785282
785261
|
});
|
|
785283
785262
|
|
|
785284
785263
|
// node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/home-graph/types.js
|
|
785285
|
-
var
|
|
785264
|
+
var HOME_GRAPH_CAPABILITIES;
|
|
785286
785265
|
var init_types15 = __esm(() => {
|
|
785287
|
-
HOME_GRAPH_NODE_KINDS = [
|
|
785288
|
-
"ha_home",
|
|
785289
|
-
"ha_entity",
|
|
785290
|
-
"ha_device",
|
|
785291
|
-
"ha_area",
|
|
785292
|
-
"ha_automation",
|
|
785293
|
-
"ha_script",
|
|
785294
|
-
"ha_scene",
|
|
785295
|
-
"ha_label",
|
|
785296
|
-
"ha_integration",
|
|
785297
|
-
"ha_room",
|
|
785298
|
-
"ha_device_passport",
|
|
785299
|
-
"ha_maintenance_item",
|
|
785300
|
-
"ha_troubleshooting_case",
|
|
785301
|
-
"ha_purchase",
|
|
785302
|
-
"ha_network_node"
|
|
785303
|
-
];
|
|
785304
|
-
HOME_GRAPH_RELATIONS = [
|
|
785305
|
-
"controls",
|
|
785306
|
-
"located_in",
|
|
785307
|
-
"belongs_to_device",
|
|
785308
|
-
"has_manual",
|
|
785309
|
-
"has_receipt",
|
|
785310
|
-
"has_warranty",
|
|
785311
|
-
"has_issue",
|
|
785312
|
-
"fixed_by",
|
|
785313
|
-
"uses_battery",
|
|
785314
|
-
"connected_via",
|
|
785315
|
-
"part_of_network",
|
|
785316
|
-
"mentioned_by",
|
|
785317
|
-
"source_for"
|
|
785318
|
-
];
|
|
785319
785266
|
HOME_GRAPH_CAPABILITIES = [
|
|
785320
785267
|
"knowledge-space-isolation",
|
|
785321
785268
|
"snapshot-sync",
|
|
@@ -786722,7 +786669,6 @@ var init_service5 = __esm(() => {
|
|
|
786722
786669
|
var init_home_graph = __esm(() => {
|
|
786723
786670
|
init_service5();
|
|
786724
786671
|
init_extension();
|
|
786725
|
-
init_types15();
|
|
786726
786672
|
});
|
|
786727
786673
|
|
|
786728
786674
|
// node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/store-refinement.js
|
|
@@ -789050,14 +788996,10 @@ var init_service6 = __esm(() => {
|
|
|
789050
788996
|
var init_project_planning = __esm(() => {
|
|
789051
788997
|
init_service6();
|
|
789052
788998
|
init_helpers3();
|
|
789053
|
-
init_readiness();
|
|
789054
788999
|
});
|
|
789055
789000
|
|
|
789056
789001
|
// node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/persistence.js
|
|
789057
|
-
var init_persistence =
|
|
789058
|
-
init_store_schema();
|
|
789059
|
-
init_store_load();
|
|
789060
|
-
});
|
|
789002
|
+
var init_persistence = () => {};
|
|
789061
789003
|
|
|
789062
789004
|
// node_modules/@pellux/goodvibes-sdk/dist/platform/knowledge/projections.js
|
|
789063
789005
|
class KnowledgeProjectionService {
|
|
@@ -792565,21 +792507,21 @@ var init_service7 = __esm(() => {
|
|
|
792565
792507
|
var exports_knowledge = {};
|
|
792566
792508
|
__export(exports_knowledge, {
|
|
792567
792509
|
withKnowledgeSpace: () => withKnowledgeSpace,
|
|
792568
|
-
uniqKnowledgeValues: () =>
|
|
792569
|
-
stabilizeKnowledgeText: () =>
|
|
792570
|
-
runKnowledgeSemanticSelfImprovement: () =>
|
|
792510
|
+
uniqKnowledgeValues: () => uniq3,
|
|
792511
|
+
stabilizeKnowledgeText: () => stableText2,
|
|
792512
|
+
runKnowledgeSemanticSelfImprovement: () => runKnowledgeSemanticSelfImprovement2,
|
|
792571
792513
|
resolveProjectPlanningSpace: () => resolveProjectPlanningSpace,
|
|
792572
|
-
resolveKnowledgeDbPathFromControlPlaneDir: () =>
|
|
792514
|
+
resolveKnowledgeDbPathFromControlPlaneDir: () => resolveKnowledgeDbPathFromControlPlaneDir2,
|
|
792573
792515
|
renderPacket: () => renderPacket,
|
|
792574
792516
|
renderKnowledgeSchemaSql: () => renderKnowledgeSchemaSql,
|
|
792575
792517
|
renderKnowledgeMap: () => renderKnowledgeMap,
|
|
792576
792518
|
readKnowledgeSearchText: () => readKnowledgeSearchText,
|
|
792577
|
-
readBrowserKnowledgeProfile: () =>
|
|
792519
|
+
readBrowserKnowledgeProfile: () => readBrowserKnowledgeProfile2,
|
|
792578
792520
|
projectPlanningSourceId: () => projectPlanningSourceId,
|
|
792579
792521
|
projectPlanningProjectIdFromPath: () => projectPlanningProjectIdFromPath,
|
|
792580
792522
|
projectPlanningCanonicalUri: () => projectPlanningCanonicalUri,
|
|
792581
792523
|
projectKnowledgeSpaceId: () => projectKnowledgeSpaceId,
|
|
792582
|
-
parseKnowledgeJsonValue: () =>
|
|
792524
|
+
parseKnowledgeJsonValue: () => parseJsonValue2,
|
|
792583
792525
|
normalizeProjectId: () => normalizeProjectId,
|
|
792584
792526
|
normalizeKnowledgeSpaceId: () => normalizeKnowledgeSpaceId,
|
|
792585
792527
|
normalizeHomeAssistantInstallationId: () => normalizeHomeAssistantInstallationId,
|
|
@@ -792587,12 +792529,12 @@ __export(exports_knowledge, {
|
|
|
792587
792529
|
materializeGeneratedKnowledgeProjection: () => materializeGeneratedKnowledgeProjection,
|
|
792588
792530
|
looksLikeRawPdfPayload: () => looksLikeRawPdfPayload,
|
|
792589
792531
|
looksBinaryLikeText: () => looksBinaryLikeText,
|
|
792590
|
-
loadKnowledgeStoreSnapshot: () =>
|
|
792532
|
+
loadKnowledgeStoreSnapshot: () => loadKnowledgeStoreSnapshot2,
|
|
792591
792533
|
listGeneratedKnowledgePages: () => listGeneratedKnowledgePages,
|
|
792592
|
-
listBrowserKinds: () =>
|
|
792534
|
+
listBrowserKinds: () => listBrowserKinds2,
|
|
792593
792535
|
knowledgeSpaceMetadata: () => knowledgeSpaceMetadata,
|
|
792594
792536
|
knowledgePageSourceWeight: () => knowledgePageSourceWeight,
|
|
792595
|
-
knowledgeNowMs: () =>
|
|
792537
|
+
knowledgeNowMs: () => nowMs2,
|
|
792596
792538
|
knowledgeExtractionNeedsRefresh: () => knowledgeExtractionNeedsRefresh,
|
|
792597
792539
|
isUsefulKnowledgePageSourceCandidate: () => isUsefulKnowledgePageSourceCandidate,
|
|
792598
792540
|
isUsefulKnowledgePageSource: () => isUsefulKnowledgePageSource,
|
|
@@ -792612,12 +792554,12 @@ __export(exports_knowledge, {
|
|
|
792612
792554
|
generatedKnowledgeSourceId: () => generatedKnowledgeSourceId,
|
|
792613
792555
|
generatedKnowledgeCanonicalUri: () => generatedKnowledgeCanonicalUri,
|
|
792614
792556
|
extractKnowledgeArtifact: () => extractKnowledgeArtifact,
|
|
792615
|
-
evaluateProjectPlanningReadiness: () =>
|
|
792616
|
-
discoverBrowserKnowledgeProfiles: () =>
|
|
792557
|
+
evaluateProjectPlanningReadiness: () => evaluateProjectPlanningReadiness2,
|
|
792558
|
+
discoverBrowserKnowledgeProfiles: () => discoverBrowserKnowledgeProfiles2,
|
|
792617
792559
|
createWebKnowledgeGapRepairer: () => createWebKnowledgeGapRepairer,
|
|
792618
792560
|
createProviderBackedKnowledgeSemanticLlm: () => createProviderBackedKnowledgeSemanticLlm,
|
|
792619
792561
|
createMemoryApi: () => createMemoryApi,
|
|
792620
|
-
createKnowledgeSchema: () =>
|
|
792562
|
+
createKnowledgeSchema: () => createSchema3,
|
|
792621
792563
|
createKnowledgeApi: () => createKnowledgeApi,
|
|
792622
792564
|
createDefaultKnowledgeConnectorRegistry: () => createDefaultKnowledgeConnectorRegistry,
|
|
792623
792565
|
compareKnowledgePageSources: () => compareKnowledgePageSources,
|
|
@@ -795056,7 +794998,7 @@ var init_delivery_manager = __esm(() => {
|
|
|
795056
794998
|
});
|
|
795057
794999
|
|
|
795058
795000
|
// node_modules/@pellux/goodvibes-sdk/dist/platform/automation/scheduler-capacity.js
|
|
795059
|
-
function computeSchedulerCapacity(slotsTotal, runs,
|
|
795001
|
+
function computeSchedulerCapacity(slotsTotal, runs, nowMs3 = Date.now()) {
|
|
795060
795002
|
let slotsInUse = 0;
|
|
795061
795003
|
const queuedRuns = [];
|
|
795062
795004
|
for (const run7 of runs) {
|
|
@@ -795066,7 +795008,7 @@ function computeSchedulerCapacity(slotsTotal, runs, nowMs2 = Date.now()) {
|
|
|
795066
795008
|
queuedRuns.push(run7);
|
|
795067
795009
|
}
|
|
795068
795010
|
const queueDepth = queuedRuns.length;
|
|
795069
|
-
const oldestQueuedAgeMs = queueDepth > 0 ?
|
|
795011
|
+
const oldestQueuedAgeMs = queueDepth > 0 ? nowMs3 - Math.min(...queuedRuns.map((r6) => r6.queuedAt)) : null;
|
|
795070
795012
|
return { slotsTotal, slotsInUse, queueDepth, oldestQueuedAgeMs };
|
|
795071
795013
|
}
|
|
795072
795014
|
|
|
@@ -817092,7 +817034,7 @@ var createStyledCell = (char, overrides = {}) => ({
|
|
|
817092
817034
|
// src/version.ts
|
|
817093
817035
|
import { readFileSync } from "fs";
|
|
817094
817036
|
import { join } from "path";
|
|
817095
|
-
var _version = "1.1.
|
|
817037
|
+
var _version = "1.1.7";
|
|
817096
817038
|
try {
|
|
817097
817039
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, "..", "package.json"), "utf-8"));
|
|
817098
817040
|
_version = typeof pkg.version === "string" ? pkg.version : _version;
|
|
@@ -839605,7 +839547,7 @@ var WORK_PLAN_STATUSES = [
|
|
|
839605
839547
|
"failed",
|
|
839606
839548
|
"cancelled"
|
|
839607
839549
|
];
|
|
839608
|
-
function
|
|
839550
|
+
function nowMs3() {
|
|
839609
839551
|
return Date.now();
|
|
839610
839552
|
}
|
|
839611
839553
|
function isObject4(value) {
|
|
@@ -839711,7 +839653,7 @@ class WorkPlanStore {
|
|
|
839711
839653
|
if (!normalizedTitle)
|
|
839712
839654
|
throw new Error("Work plan item title is required.");
|
|
839713
839655
|
const plan = this.readPlan();
|
|
839714
|
-
const time4 =
|
|
839656
|
+
const time4 = nowMs3();
|
|
839715
839657
|
const item = {
|
|
839716
839658
|
id: createItemId(),
|
|
839717
839659
|
title: normalizedTitle,
|
|
@@ -839735,7 +839677,7 @@ class WorkPlanStore {
|
|
|
839735
839677
|
updateItem(idOrPrefix, patch2) {
|
|
839736
839678
|
const plan = this.readPlan();
|
|
839737
839679
|
const item = this.resolveItem(plan, idOrPrefix);
|
|
839738
|
-
const time4 =
|
|
839680
|
+
const time4 = nowMs3();
|
|
839739
839681
|
const nextStatus = patch2.status ?? item.status;
|
|
839740
839682
|
const next = this.pruneItem({
|
|
839741
839683
|
...item,
|
|
@@ -839768,7 +839710,7 @@ class WorkPlanStore {
|
|
|
839768
839710
|
removeItem(idOrPrefix) {
|
|
839769
839711
|
const plan = this.readPlan();
|
|
839770
839712
|
const item = this.resolveItem(plan, idOrPrefix);
|
|
839771
|
-
const time4 =
|
|
839713
|
+
const time4 = nowMs3();
|
|
839772
839714
|
const remaining = plan.items.filter((candidate) => candidate.id !== item.id);
|
|
839773
839715
|
this.writePlan({
|
|
839774
839716
|
...plan,
|
|
@@ -839788,7 +839730,7 @@ class WorkPlanStore {
|
|
|
839788
839730
|
...plan,
|
|
839789
839731
|
items: remaining,
|
|
839790
839732
|
activeItemId: remaining[0]?.id,
|
|
839791
|
-
updatedAt:
|
|
839733
|
+
updatedAt: nowMs3()
|
|
839792
839734
|
});
|
|
839793
839735
|
return removed;
|
|
839794
839736
|
}
|
|
@@ -839827,7 +839769,7 @@ class WorkPlanStore {
|
|
|
839827
839769
|
const parsed = JSON.parse(raw);
|
|
839828
839770
|
if (!isObject4(parsed))
|
|
839829
839771
|
return this.createEmptyPlan();
|
|
839830
|
-
const time4 =
|
|
839772
|
+
const time4 = nowMs3();
|
|
839831
839773
|
const createdAt = typeof parsed.createdAt === "number" ? parsed.createdAt : time4;
|
|
839832
839774
|
const updatedAt = typeof parsed.updatedAt === "number" ? parsed.updatedAt : createdAt;
|
|
839833
839775
|
const items = Array.isArray(parsed.items) ? parsed.items.map((item) => normalizeItem(item, createdAt)).filter((item) => item !== null) : [];
|
|
@@ -839846,7 +839788,7 @@ class WorkPlanStore {
|
|
|
839846
839788
|
};
|
|
839847
839789
|
}
|
|
839848
839790
|
createEmptyPlan() {
|
|
839849
|
-
const time4 =
|
|
839791
|
+
const time4 = nowMs3();
|
|
839850
839792
|
return {
|
|
839851
839793
|
id: createPlanId(this.options.projectId, this.options.projectRoot),
|
|
839852
839794
|
projectId: this.options.projectId,
|
|
@@ -840631,20 +840573,132 @@ function isRecord17(value) {
|
|
|
840631
840573
|
}
|
|
840632
840574
|
|
|
840633
840575
|
// src/tools/agent-context-policy.ts
|
|
840634
|
-
var
|
|
840635
|
-
"
|
|
840636
|
-
"
|
|
840637
|
-
"
|
|
840638
|
-
|
|
840639
|
-
|
|
840640
|
-
|
|
840576
|
+
var AGENT_CONTEXT_TOOL_MODES = [
|
|
840577
|
+
"summary",
|
|
840578
|
+
"capabilities",
|
|
840579
|
+
"modes",
|
|
840580
|
+
"tools",
|
|
840581
|
+
"tool",
|
|
840582
|
+
"settings",
|
|
840583
|
+
"setting",
|
|
840584
|
+
"commands",
|
|
840585
|
+
"command",
|
|
840586
|
+
"workspace",
|
|
840587
|
+
"status"
|
|
840588
|
+
];
|
|
840589
|
+
var CONTEXT_TOOL_FALLBACK = {
|
|
840590
|
+
runtime: "GoodVibes Agent",
|
|
840591
|
+
preferredTool: "agent_harness",
|
|
840592
|
+
routes: {
|
|
840593
|
+
summary: 'agent_harness mode:"summary"',
|
|
840594
|
+
capabilities: 'agent_harness mode:"summary" includeParameters:true',
|
|
840595
|
+
tools: 'agent_harness mode:"tools"',
|
|
840596
|
+
tool: 'agent_harness mode:"tool"',
|
|
840597
|
+
settings: 'agent_harness mode:"settings"',
|
|
840598
|
+
commands: 'agent_harness mode:"commands"',
|
|
840599
|
+
workspace: 'agent_harness mode:"workspace"',
|
|
840600
|
+
status: 'agent_harness mode:"connected_host_status"'
|
|
840601
|
+
}
|
|
840602
|
+
};
|
|
840603
|
+
function wrapAgentContextToolForAgentPolicy(tool2, registry5) {
|
|
840604
|
+
tool2.definition.description = "Inspect GoodVibes Agent harness capabilities.";
|
|
840641
840605
|
tool2.definition.sideEffects = [];
|
|
840642
840606
|
tool2.definition.parameters = {
|
|
840643
840607
|
type: "object",
|
|
840644
|
-
properties: {
|
|
840608
|
+
properties: {
|
|
840609
|
+
mode: { type: "string", enum: [...AGENT_CONTEXT_TOOL_MODES] },
|
|
840610
|
+
query: { type: "string" },
|
|
840611
|
+
target: { type: "string" },
|
|
840612
|
+
toolName: { type: "string" },
|
|
840613
|
+
command: { type: "string" },
|
|
840614
|
+
commandName: { type: "string" },
|
|
840615
|
+
key: { type: "string" },
|
|
840616
|
+
category: { type: "string" },
|
|
840617
|
+
prefix: { type: "string" },
|
|
840618
|
+
includeHidden: { type: "boolean" },
|
|
840619
|
+
includeParameters: { type: "boolean" },
|
|
840620
|
+
limit: { type: "number" }
|
|
840621
|
+
},
|
|
840645
840622
|
additionalProperties: false
|
|
840646
840623
|
};
|
|
840647
|
-
tool2.execute = async () =>
|
|
840624
|
+
tool2.execute = async (rawArgs) => {
|
|
840625
|
+
const args2 = rawArgs;
|
|
840626
|
+
const mode = readAgentContextMode(args2.mode);
|
|
840627
|
+
const harnessMode = agentContextModeToHarnessMode(mode);
|
|
840628
|
+
const harnessTool = registry5?.list().find((entry) => entry.definition.name === "agent_harness");
|
|
840629
|
+
if (!harnessTool) {
|
|
840630
|
+
return ok3({
|
|
840631
|
+
...CONTEXT_TOOL_FALLBACK,
|
|
840632
|
+
status: "agent_harness_not_registered_yet",
|
|
840633
|
+
requestedMode: mode,
|
|
840634
|
+
route: `agent_harness mode:"${harnessMode}"`
|
|
840635
|
+
});
|
|
840636
|
+
}
|
|
840637
|
+
const harnessArgs = {
|
|
840638
|
+
mode: harnessMode,
|
|
840639
|
+
query: args2.query,
|
|
840640
|
+
target: args2.target,
|
|
840641
|
+
toolName: args2.toolName,
|
|
840642
|
+
command: args2.command,
|
|
840643
|
+
commandName: args2.commandName,
|
|
840644
|
+
key: args2.key,
|
|
840645
|
+
category: args2.category,
|
|
840646
|
+
prefix: args2.prefix,
|
|
840647
|
+
includeHidden: args2.includeHidden,
|
|
840648
|
+
includeParameters: mode === "capabilities" ? true : args2.includeParameters,
|
|
840649
|
+
limit: args2.limit
|
|
840650
|
+
};
|
|
840651
|
+
const result2 = await harnessTool.execute(dropUndefined(harnessArgs));
|
|
840652
|
+
if (!result2.success)
|
|
840653
|
+
return result2;
|
|
840654
|
+
return ok3({
|
|
840655
|
+
source: "agent_harness",
|
|
840656
|
+
requestedMode: mode,
|
|
840657
|
+
route: `agent_harness mode:"${harnessMode}"`,
|
|
840658
|
+
result: parseToolOutput2(result2.output)
|
|
840659
|
+
});
|
|
840660
|
+
};
|
|
840661
|
+
}
|
|
840662
|
+
function readAgentContextMode(value) {
|
|
840663
|
+
return typeof value === "string" && AGENT_CONTEXT_TOOL_MODES.includes(value) ? value : "summary";
|
|
840664
|
+
}
|
|
840665
|
+
function agentContextModeToHarnessMode(mode) {
|
|
840666
|
+
if (mode === "capabilities")
|
|
840667
|
+
return "summary";
|
|
840668
|
+
if (mode === "modes")
|
|
840669
|
+
return "modes";
|
|
840670
|
+
if (mode === "tools")
|
|
840671
|
+
return "tools";
|
|
840672
|
+
if (mode === "tool")
|
|
840673
|
+
return "tool";
|
|
840674
|
+
if (mode === "settings")
|
|
840675
|
+
return "settings";
|
|
840676
|
+
if (mode === "setting")
|
|
840677
|
+
return "get_setting";
|
|
840678
|
+
if (mode === "commands")
|
|
840679
|
+
return "commands";
|
|
840680
|
+
if (mode === "command")
|
|
840681
|
+
return "command";
|
|
840682
|
+
if (mode === "workspace")
|
|
840683
|
+
return "workspace";
|
|
840684
|
+
if (mode === "status")
|
|
840685
|
+
return "connected_host_status";
|
|
840686
|
+
return "summary";
|
|
840687
|
+
}
|
|
840688
|
+
function dropUndefined(value) {
|
|
840689
|
+
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
|
|
840690
|
+
}
|
|
840691
|
+
function parseToolOutput2(value) {
|
|
840692
|
+
if (typeof value !== "string")
|
|
840693
|
+
return value ?? null;
|
|
840694
|
+
try {
|
|
840695
|
+
return JSON.parse(value);
|
|
840696
|
+
} catch {
|
|
840697
|
+
return value;
|
|
840698
|
+
}
|
|
840699
|
+
}
|
|
840700
|
+
function ok3(value) {
|
|
840701
|
+
return { success: true, output: JSON.stringify(value, null, 2) };
|
|
840648
840702
|
}
|
|
840649
840703
|
|
|
840650
840704
|
// src/tools/agent-find-policy.ts
|
|
@@ -841115,7 +841169,7 @@ function installAgentToolPolicyGuard(registry5, options = {}) {
|
|
|
841115
841169
|
} else if (tool2.definition.name === "state") {
|
|
841116
841170
|
wrapStateToolForAgentPolicy(tool2);
|
|
841117
841171
|
} else if (tool2.definition.name === "goodvibes_context") {
|
|
841118
|
-
|
|
841172
|
+
wrapAgentContextToolForAgentPolicy(tool2, registry5);
|
|
841119
841173
|
} else if (tool2.definition.name === "goodvibes_settings") {
|
|
841120
841174
|
wrapBlockedSettingsToolForAgentPolicy(tool2);
|
|
841121
841175
|
} else if (tool2.definition.name === "inspect") {
|
|
@@ -848607,6 +848661,119 @@ function compactRegisteredToolDefinitions(toolRegistry) {
|
|
|
848607
848661
|
}
|
|
848608
848662
|
}
|
|
848609
848663
|
|
|
848664
|
+
// src/tools/tool-execution-safety.ts
|
|
848665
|
+
var TOOL_SAFETY_MARKER = Symbol.for("goodvibes-agent.tool-execution-safety-wrapped");
|
|
848666
|
+
var REGISTRY_SAFETY_MARKER = Symbol.for("goodvibes-agent.tool-registry-safety-installed");
|
|
848667
|
+
function installToolExecutionSafetyGuard(registry5) {
|
|
848668
|
+
const marked = registry5;
|
|
848669
|
+
if (marked[REGISTRY_SAFETY_MARKER])
|
|
848670
|
+
return;
|
|
848671
|
+
marked[REGISTRY_SAFETY_MARKER] = true;
|
|
848672
|
+
for (const tool2 of registry5.list())
|
|
848673
|
+
wrapToolExecutionSafety(tool2);
|
|
848674
|
+
const originalRegister = registry5.register.bind(registry5);
|
|
848675
|
+
registry5.register = (tool2) => {
|
|
848676
|
+
wrapToolExecutionSafety(tool2);
|
|
848677
|
+
originalRegister(tool2);
|
|
848678
|
+
};
|
|
848679
|
+
}
|
|
848680
|
+
function wrapToolExecutionSafety(tool2) {
|
|
848681
|
+
const marked = tool2;
|
|
848682
|
+
if (marked[TOOL_SAFETY_MARKER])
|
|
848683
|
+
return;
|
|
848684
|
+
marked[TOOL_SAFETY_MARKER] = true;
|
|
848685
|
+
const originalExecute = tool2.execute.bind(tool2);
|
|
848686
|
+
tool2.execute = async (args2) => {
|
|
848687
|
+
try {
|
|
848688
|
+
return await originalExecute(args2);
|
|
848689
|
+
} catch (error51) {
|
|
848690
|
+
return {
|
|
848691
|
+
success: false,
|
|
848692
|
+
error: summarizeError(error51)
|
|
848693
|
+
};
|
|
848694
|
+
}
|
|
848695
|
+
};
|
|
848696
|
+
}
|
|
848697
|
+
|
|
848698
|
+
// src/runtime/tool-permission-safety.ts
|
|
848699
|
+
var SAFETY_MARKER = Symbol.for("goodvibes-agent.permission-safety-installed");
|
|
848700
|
+
var READ_TOOL_NAMES = new Set([
|
|
848701
|
+
"read",
|
|
848702
|
+
"find",
|
|
848703
|
+
"fetch",
|
|
848704
|
+
"analyze",
|
|
848705
|
+
"inspect",
|
|
848706
|
+
"state",
|
|
848707
|
+
"registry",
|
|
848708
|
+
"goodvibes_context",
|
|
848709
|
+
"agent_harness",
|
|
848710
|
+
"agent_knowledge",
|
|
848711
|
+
"agent_operator_briefing"
|
|
848712
|
+
]);
|
|
848713
|
+
var WRITE_TOOL_NAMES = new Set([
|
|
848714
|
+
"write",
|
|
848715
|
+
"edit",
|
|
848716
|
+
"goodvibes_settings",
|
|
848717
|
+
"agent_knowledge_ingest",
|
|
848718
|
+
"agent_local_registry",
|
|
848719
|
+
"agent_work_plan"
|
|
848720
|
+
]);
|
|
848721
|
+
var EXECUTE_TOOL_NAMES = new Set(["exec", "repl"]);
|
|
848722
|
+
function installPermissionManagerSafetyGuard(manager5) {
|
|
848723
|
+
const marked = manager5;
|
|
848724
|
+
if (marked[SAFETY_MARKER])
|
|
848725
|
+
return;
|
|
848726
|
+
marked[SAFETY_MARKER] = true;
|
|
848727
|
+
const originalGetCategory = manager5.getCategory.bind(manager5);
|
|
848728
|
+
const originalCheck = manager5.check.bind(manager5);
|
|
848729
|
+
const originalCheckDetailed = manager5.checkDetailed?.bind(manager5);
|
|
848730
|
+
manager5.getCategory = (toolName, args2 = {}) => {
|
|
848731
|
+
try {
|
|
848732
|
+
return originalGetCategory(toolName, args2);
|
|
848733
|
+
} catch {
|
|
848734
|
+
return fallbackPermissionCategory(toolName);
|
|
848735
|
+
}
|
|
848736
|
+
};
|
|
848737
|
+
manager5.check = async (toolName, args2) => {
|
|
848738
|
+
try {
|
|
848739
|
+
return await originalCheck(toolName, args2);
|
|
848740
|
+
} catch {
|
|
848741
|
+
return fallbackPermissionCategory(toolName) === "read";
|
|
848742
|
+
}
|
|
848743
|
+
};
|
|
848744
|
+
if (originalCheckDetailed) {
|
|
848745
|
+
manager5.checkDetailed = async (toolName, args2) => {
|
|
848746
|
+
try {
|
|
848747
|
+
return await originalCheckDetailed(toolName, args2);
|
|
848748
|
+
} catch (error51) {
|
|
848749
|
+
const category = fallbackPermissionCategory(toolName);
|
|
848750
|
+
const approved = category === "read";
|
|
848751
|
+
return {
|
|
848752
|
+
approved,
|
|
848753
|
+
persisted: false,
|
|
848754
|
+
sourceLayer: "runtime_mode",
|
|
848755
|
+
reasonCode: approved ? "config_allow" : "config_deny",
|
|
848756
|
+
analysis: {
|
|
848757
|
+
classification: "generic",
|
|
848758
|
+
riskLevel: category === "read" ? "low" : "high",
|
|
848759
|
+
summary: `Permission fallback for ${toolName}: ${summarizeError(error51)}`,
|
|
848760
|
+
reasons: ["permission-manager-exception"]
|
|
848761
|
+
}
|
|
848762
|
+
};
|
|
848763
|
+
}
|
|
848764
|
+
};
|
|
848765
|
+
}
|
|
848766
|
+
}
|
|
848767
|
+
function fallbackPermissionCategory(toolName) {
|
|
848768
|
+
if (READ_TOOL_NAMES.has(toolName))
|
|
848769
|
+
return "read";
|
|
848770
|
+
if (WRITE_TOOL_NAMES.has(toolName))
|
|
848771
|
+
return "write";
|
|
848772
|
+
if (EXECUTE_TOOL_NAMES.has(toolName))
|
|
848773
|
+
return "execute";
|
|
848774
|
+
return "delegate";
|
|
848775
|
+
}
|
|
848776
|
+
|
|
848610
848777
|
// src/runtime/agent-runtime-events.ts
|
|
848611
848778
|
var AGENT_STATUS_INTERVAL_MS2 = 30000;
|
|
848612
848779
|
function withRouter2(getSystemMessageRouter, action2) {
|
|
@@ -848863,6 +849030,7 @@ async function initializeBootstrapCore(stdout, options, getControlPlaneRecentEve
|
|
|
848863
849030
|
installAgentToolPolicyGuard(toolRegistry, {
|
|
848864
849031
|
getLastUserMessage: () => conversation.getLastUserMessage()
|
|
848865
849032
|
});
|
|
849033
|
+
installToolExecutionSafetyGuard(toolRegistry);
|
|
848866
849034
|
compactRegisteredToolDefinitions(toolRegistry);
|
|
848867
849035
|
services.agentOrchestrator.setDependencies({
|
|
848868
849036
|
surfaceRoot: GOODVIBES_AGENT_SURFACE_ROOT,
|
|
@@ -849001,6 +849169,7 @@ async function initializeBootstrapCore(stdout, options, getControlPlaneRecentEve
|
|
|
849001
849169
|
sessionId: runtimeSessionIdRef.value,
|
|
849002
849170
|
localPrompt: permissionPromptRef.requestPermission
|
|
849003
849171
|
}), createPermissionConfigReader(configManager), policyRuntimeState, services.hookDispatcher, featureFlags);
|
|
849172
|
+
installPermissionManagerSafetyGuard(permissionManager);
|
|
849004
849173
|
await hookWorkbench.loadAndApplyManagedHooks();
|
|
849005
849174
|
const runtime2 = {
|
|
849006
849175
|
model: configManager.get("provider.model"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-agent",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "GoodVibes personal operator assistant TUI with a proactive Agent product brain, isolated Agent Knowledge, local profiles, routines, skills, personas, and explicit build delegation.",
|
|
6
6
|
"type": "module",
|
|
@@ -41,6 +41,8 @@ import { registerAgentReminderScheduleTool } from '../tools/agent-reminder-sched
|
|
|
41
41
|
import { getTerminalSize } from '../shell/terminal-size.ts';
|
|
42
42
|
import { registerAgentWorkPlanTool } from '../tools/agent-work-plan-tool.ts';
|
|
43
43
|
import { compactRegisteredToolDefinitions } from '../tools/tool-definition-compaction.ts';
|
|
44
|
+
import { installToolExecutionSafetyGuard } from '../tools/tool-execution-safety.ts';
|
|
45
|
+
import { installPermissionManagerSafetyGuard } from './tool-permission-safety.ts';
|
|
44
46
|
import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
|
|
45
47
|
import { registerAgentRuntimeEvents } from './agent-runtime-events.ts';
|
|
46
48
|
|
|
@@ -251,6 +253,7 @@ export async function initializeBootstrapCore(
|
|
|
251
253
|
installAgentToolPolicyGuard(toolRegistry, {
|
|
252
254
|
getLastUserMessage: () => conversation.getLastUserMessage(),
|
|
253
255
|
});
|
|
256
|
+
installToolExecutionSafetyGuard(toolRegistry);
|
|
254
257
|
compactRegisteredToolDefinitions(toolRegistry);
|
|
255
258
|
services.agentOrchestrator.setDependencies({
|
|
256
259
|
surfaceRoot: GOODVIBES_AGENT_SURFACE_ROOT,
|
|
@@ -432,6 +435,7 @@ export async function initializeBootstrapCore(
|
|
|
432
435
|
services.hookDispatcher,
|
|
433
436
|
featureFlags,
|
|
434
437
|
);
|
|
438
|
+
installPermissionManagerSafetyGuard(permissionManager);
|
|
435
439
|
await hookWorkbench.loadAndApplyManagedHooks();
|
|
436
440
|
|
|
437
441
|
const runtime: MutableRuntimeState = {
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { PermissionCategory, PermissionCheckResult } from '@pellux/goodvibes-sdk/platform/permissions';
|
|
2
|
+
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
3
|
+
|
|
4
|
+
type PermissionManagerLike = {
|
|
5
|
+
check(toolName: string, args: Record<string, unknown>): Promise<boolean>;
|
|
6
|
+
checkDetailed?: (toolName: string, args: Record<string, unknown>) => Promise<PermissionCheckResult>;
|
|
7
|
+
getCategory(toolName: string, args?: Record<string, unknown>): PermissionCategory;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const SAFETY_MARKER = Symbol.for('goodvibes-agent.permission-safety-installed');
|
|
11
|
+
|
|
12
|
+
const READ_TOOL_NAMES = new Set([
|
|
13
|
+
'read',
|
|
14
|
+
'find',
|
|
15
|
+
'fetch',
|
|
16
|
+
'analyze',
|
|
17
|
+
'inspect',
|
|
18
|
+
'state',
|
|
19
|
+
'registry',
|
|
20
|
+
'goodvibes_context',
|
|
21
|
+
'agent_harness',
|
|
22
|
+
'agent_knowledge',
|
|
23
|
+
'agent_operator_briefing',
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
const WRITE_TOOL_NAMES = new Set([
|
|
27
|
+
'write',
|
|
28
|
+
'edit',
|
|
29
|
+
'goodvibes_settings',
|
|
30
|
+
'agent_knowledge_ingest',
|
|
31
|
+
'agent_local_registry',
|
|
32
|
+
'agent_work_plan',
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
const EXECUTE_TOOL_NAMES = new Set(['exec', 'repl']);
|
|
36
|
+
|
|
37
|
+
type MarkedPermissionManager = PermissionManagerLike & { [SAFETY_MARKER]?: true };
|
|
38
|
+
|
|
39
|
+
export function installPermissionManagerSafetyGuard(manager: PermissionManagerLike): void {
|
|
40
|
+
const marked = manager as MarkedPermissionManager;
|
|
41
|
+
if (marked[SAFETY_MARKER]) return;
|
|
42
|
+
marked[SAFETY_MARKER] = true;
|
|
43
|
+
|
|
44
|
+
const originalGetCategory = manager.getCategory.bind(manager);
|
|
45
|
+
const originalCheck = manager.check.bind(manager);
|
|
46
|
+
const originalCheckDetailed = manager.checkDetailed?.bind(manager);
|
|
47
|
+
|
|
48
|
+
manager.getCategory = (toolName, args = {}) => {
|
|
49
|
+
try {
|
|
50
|
+
return originalGetCategory(toolName, args);
|
|
51
|
+
} catch {
|
|
52
|
+
return fallbackPermissionCategory(toolName);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
manager.check = async (toolName, args) => {
|
|
57
|
+
try {
|
|
58
|
+
return await originalCheck(toolName, args);
|
|
59
|
+
} catch {
|
|
60
|
+
return fallbackPermissionCategory(toolName) === 'read';
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
if (originalCheckDetailed) {
|
|
65
|
+
manager.checkDetailed = async (toolName, args) => {
|
|
66
|
+
try {
|
|
67
|
+
return await originalCheckDetailed(toolName, args);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
const category = fallbackPermissionCategory(toolName);
|
|
70
|
+
const approved = category === 'read';
|
|
71
|
+
return {
|
|
72
|
+
approved,
|
|
73
|
+
persisted: false,
|
|
74
|
+
sourceLayer: 'runtime_mode',
|
|
75
|
+
reasonCode: approved ? 'config_allow' : 'config_deny',
|
|
76
|
+
analysis: {
|
|
77
|
+
classification: 'generic',
|
|
78
|
+
riskLevel: category === 'read' ? 'low' : 'high',
|
|
79
|
+
summary: `Permission fallback for ${toolName}: ${summarizeError(error)}`,
|
|
80
|
+
reasons: ['permission-manager-exception'],
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function fallbackPermissionCategory(toolName: string): PermissionCategory {
|
|
89
|
+
if (READ_TOOL_NAMES.has(toolName)) return 'read';
|
|
90
|
+
if (WRITE_TOOL_NAMES.has(toolName)) return 'write';
|
|
91
|
+
if (EXECUTE_TOOL_NAMES.has(toolName)) return 'execute';
|
|
92
|
+
return 'delegate';
|
|
93
|
+
}
|
|
@@ -1,20 +1,147 @@
|
|
|
1
1
|
import type { Tool } from '@pellux/goodvibes-sdk/platform/types';
|
|
2
|
+
import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
|
|
2
3
|
|
|
3
|
-
const
|
|
4
|
-
'
|
|
5
|
-
'
|
|
6
|
-
'
|
|
7
|
-
|
|
4
|
+
const AGENT_CONTEXT_TOOL_MODES = [
|
|
5
|
+
'summary',
|
|
6
|
+
'capabilities',
|
|
7
|
+
'modes',
|
|
8
|
+
'tools',
|
|
9
|
+
'tool',
|
|
10
|
+
'settings',
|
|
11
|
+
'setting',
|
|
12
|
+
'commands',
|
|
13
|
+
'command',
|
|
14
|
+
'workspace',
|
|
15
|
+
'status',
|
|
16
|
+
] as const;
|
|
8
17
|
|
|
9
|
-
|
|
10
|
-
|
|
18
|
+
type AgentContextMode = typeof AGENT_CONTEXT_TOOL_MODES[number];
|
|
19
|
+
|
|
20
|
+
type AgentContextArgs = {
|
|
21
|
+
readonly mode?: unknown;
|
|
22
|
+
readonly query?: unknown;
|
|
23
|
+
readonly target?: unknown;
|
|
24
|
+
readonly toolName?: unknown;
|
|
25
|
+
readonly command?: unknown;
|
|
26
|
+
readonly commandName?: unknown;
|
|
27
|
+
readonly key?: unknown;
|
|
28
|
+
readonly category?: unknown;
|
|
29
|
+
readonly prefix?: unknown;
|
|
30
|
+
readonly includeHidden?: unknown;
|
|
31
|
+
readonly includeParameters?: unknown;
|
|
32
|
+
readonly limit?: unknown;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const CONTEXT_TOOL_FALLBACK = {
|
|
36
|
+
runtime: 'GoodVibes Agent',
|
|
37
|
+
preferredTool: 'agent_harness',
|
|
38
|
+
routes: {
|
|
39
|
+
summary: 'agent_harness mode:"summary"',
|
|
40
|
+
capabilities: 'agent_harness mode:"summary" includeParameters:true',
|
|
41
|
+
tools: 'agent_harness mode:"tools"',
|
|
42
|
+
tool: 'agent_harness mode:"tool"',
|
|
43
|
+
settings: 'agent_harness mode:"settings"',
|
|
44
|
+
commands: 'agent_harness mode:"commands"',
|
|
45
|
+
workspace: 'agent_harness mode:"workspace"',
|
|
46
|
+
status: 'agent_harness mode:"connected_host_status"',
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export function wrapAgentContextToolForAgentPolicy(tool: Tool, registry?: ToolRegistry): void {
|
|
51
|
+
tool.definition.description = 'Inspect GoodVibes Agent harness capabilities.';
|
|
11
52
|
tool.definition.sideEffects = [];
|
|
12
53
|
tool.definition.parameters = {
|
|
13
54
|
type: 'object',
|
|
14
|
-
properties: {
|
|
55
|
+
properties: {
|
|
56
|
+
mode: { type: 'string', enum: [...AGENT_CONTEXT_TOOL_MODES] },
|
|
57
|
+
query: { type: 'string' },
|
|
58
|
+
target: { type: 'string' },
|
|
59
|
+
toolName: { type: 'string' },
|
|
60
|
+
command: { type: 'string' },
|
|
61
|
+
commandName: { type: 'string' },
|
|
62
|
+
key: { type: 'string' },
|
|
63
|
+
category: { type: 'string' },
|
|
64
|
+
prefix: { type: 'string' },
|
|
65
|
+
includeHidden: { type: 'boolean' },
|
|
66
|
+
includeParameters: { type: 'boolean' },
|
|
67
|
+
limit: { type: 'number' },
|
|
68
|
+
},
|
|
15
69
|
additionalProperties: false,
|
|
16
70
|
};
|
|
17
|
-
tool.execute = async () =>
|
|
71
|
+
tool.execute = async (rawArgs) => {
|
|
72
|
+
const args = rawArgs as AgentContextArgs;
|
|
73
|
+
const mode = readAgentContextMode(args.mode);
|
|
74
|
+
const harnessMode = agentContextModeToHarnessMode(mode);
|
|
75
|
+
const harnessTool = registry?.list().find((entry) => entry.definition.name === 'agent_harness');
|
|
76
|
+
if (!harnessTool) {
|
|
77
|
+
return ok({
|
|
78
|
+
...CONTEXT_TOOL_FALLBACK,
|
|
79
|
+
status: 'agent_harness_not_registered_yet',
|
|
80
|
+
requestedMode: mode,
|
|
81
|
+
route: `agent_harness mode:"${harnessMode}"`,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const harnessArgs = {
|
|
86
|
+
mode: harnessMode,
|
|
87
|
+
query: args.query,
|
|
88
|
+
target: args.target,
|
|
89
|
+
toolName: args.toolName,
|
|
90
|
+
command: args.command,
|
|
91
|
+
commandName: args.commandName,
|
|
92
|
+
key: args.key,
|
|
93
|
+
category: args.category,
|
|
94
|
+
prefix: args.prefix,
|
|
95
|
+
includeHidden: args.includeHidden,
|
|
96
|
+
includeParameters: mode === 'capabilities' ? true : args.includeParameters,
|
|
97
|
+
limit: args.limit,
|
|
98
|
+
};
|
|
99
|
+
const result = await harnessTool.execute(dropUndefined(harnessArgs));
|
|
100
|
+
if (!result.success) return result;
|
|
101
|
+
return ok({
|
|
102
|
+
source: 'agent_harness',
|
|
103
|
+
requestedMode: mode,
|
|
104
|
+
route: `agent_harness mode:"${harnessMode}"`,
|
|
105
|
+
result: parseToolOutput(result.output),
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export const AGENT_CONTEXT_TOOL_COMPATIBILITY_MODES = AGENT_CONTEXT_TOOL_MODES;
|
|
111
|
+
|
|
112
|
+
function readAgentContextMode(value: unknown): AgentContextMode {
|
|
113
|
+
return typeof value === 'string' && AGENT_CONTEXT_TOOL_MODES.includes(value as AgentContextMode)
|
|
114
|
+
? value as AgentContextMode
|
|
115
|
+
: 'summary';
|
|
18
116
|
}
|
|
19
117
|
|
|
20
|
-
|
|
118
|
+
function agentContextModeToHarnessMode(mode: AgentContextMode): string {
|
|
119
|
+
if (mode === 'capabilities') return 'summary';
|
|
120
|
+
if (mode === 'modes') return 'modes';
|
|
121
|
+
if (mode === 'tools') return 'tools';
|
|
122
|
+
if (mode === 'tool') return 'tool';
|
|
123
|
+
if (mode === 'settings') return 'settings';
|
|
124
|
+
if (mode === 'setting') return 'get_setting';
|
|
125
|
+
if (mode === 'commands') return 'commands';
|
|
126
|
+
if (mode === 'command') return 'command';
|
|
127
|
+
if (mode === 'workspace') return 'workspace';
|
|
128
|
+
if (mode === 'status') return 'connected_host_status';
|
|
129
|
+
return 'summary';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function dropUndefined<T extends Record<string, unknown>>(value: T): Record<string, unknown> {
|
|
133
|
+
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function parseToolOutput(value: unknown): unknown {
|
|
137
|
+
if (typeof value !== 'string') return value ?? null;
|
|
138
|
+
try {
|
|
139
|
+
return JSON.parse(value);
|
|
140
|
+
} catch {
|
|
141
|
+
return value;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function ok(value: unknown): { readonly success: true; readonly output: string } {
|
|
146
|
+
return { success: true, output: JSON.stringify(value, null, 2) };
|
|
147
|
+
}
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
wrapRegistryToolForAgentPolicy,
|
|
6
6
|
} from './agent-analysis-registry-policy.ts';
|
|
7
7
|
import {
|
|
8
|
-
|
|
8
|
+
wrapAgentContextToolForAgentPolicy,
|
|
9
9
|
} from './agent-context-policy.ts';
|
|
10
10
|
import { wrapFindToolForAgentPolicy } from './agent-find-policy.ts';
|
|
11
11
|
import { wrapReadToolForAgentPolicy } from './agent-read-policy.ts';
|
|
@@ -223,7 +223,7 @@ export function installAgentToolPolicyGuard(registry: ToolRegistry, options: Age
|
|
|
223
223
|
} else if (tool.definition.name === 'state') {
|
|
224
224
|
wrapStateToolForAgentPolicy(tool);
|
|
225
225
|
} else if (tool.definition.name === 'goodvibes_context') {
|
|
226
|
-
|
|
226
|
+
wrapAgentContextToolForAgentPolicy(tool, registry);
|
|
227
227
|
} else if (tool.definition.name === 'goodvibes_settings') {
|
|
228
228
|
wrapBlockedSettingsToolForAgentPolicy(tool);
|
|
229
229
|
} else if (tool.definition.name === 'inspect') {
|
|
@@ -538,8 +538,8 @@ export const AGENT_DURABLE_WORKFLOW_MUTATION_DENIAL_MESSAGE = DURABLE_WORKFLOW_M
|
|
|
538
538
|
export const AGENT_CONTROL_MUTATION_DENIAL_MESSAGE = CONTROL_MUTATION_DENIAL;
|
|
539
539
|
|
|
540
540
|
export {
|
|
541
|
-
|
|
542
|
-
|
|
541
|
+
AGENT_CONTEXT_TOOL_COMPATIBILITY_MODES,
|
|
542
|
+
wrapAgentContextToolForAgentPolicy,
|
|
543
543
|
} from './agent-context-policy.ts';
|
|
544
544
|
|
|
545
545
|
export {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Tool } from '@pellux/goodvibes-sdk/platform/types';
|
|
2
|
+
import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
|
|
3
|
+
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
4
|
+
|
|
5
|
+
const TOOL_SAFETY_MARKER = Symbol.for('goodvibes-agent.tool-execution-safety-wrapped');
|
|
6
|
+
const REGISTRY_SAFETY_MARKER = Symbol.for('goodvibes-agent.tool-registry-safety-installed');
|
|
7
|
+
|
|
8
|
+
type MarkedTool = Tool & { [TOOL_SAFETY_MARKER]?: true };
|
|
9
|
+
type MarkedRegistry = ToolRegistry & { [REGISTRY_SAFETY_MARKER]?: true };
|
|
10
|
+
|
|
11
|
+
export function installToolExecutionSafetyGuard(registry: ToolRegistry): void {
|
|
12
|
+
const marked = registry as MarkedRegistry;
|
|
13
|
+
if (marked[REGISTRY_SAFETY_MARKER]) return;
|
|
14
|
+
marked[REGISTRY_SAFETY_MARKER] = true;
|
|
15
|
+
|
|
16
|
+
for (const tool of registry.list()) wrapToolExecutionSafety(tool);
|
|
17
|
+
|
|
18
|
+
const originalRegister = registry.register.bind(registry);
|
|
19
|
+
registry.register = (tool: Tool): void => {
|
|
20
|
+
wrapToolExecutionSafety(tool);
|
|
21
|
+
originalRegister(tool);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function wrapToolExecutionSafety(tool: Tool): void {
|
|
26
|
+
const marked = tool as MarkedTool;
|
|
27
|
+
if (marked[TOOL_SAFETY_MARKER]) return;
|
|
28
|
+
marked[TOOL_SAFETY_MARKER] = true;
|
|
29
|
+
|
|
30
|
+
const originalExecute = tool.execute.bind(tool);
|
|
31
|
+
tool.execute = async (args) => {
|
|
32
|
+
try {
|
|
33
|
+
return await originalExecute(args);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
return {
|
|
36
|
+
success: false,
|
|
37
|
+
error: summarizeError(error),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
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.1.
|
|
9
|
+
let _version = '1.1.7';
|
|
10
10
|
try {
|
|
11
11
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8')) as {
|
|
12
12
|
readonly version?: unknown;
|