Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c9f1122
v0.1.2: Fix deprecated dependencies and CI stability (#4)
ApiliumDevTeam Mar 2, 2026
e624111
Bump the docker-images group with 2 updates
dependabot[bot] Mar 2, 2026
50f1db2
Bump the docker-images group with 2 updates (#5)
ApiliumDevTeam Mar 2, 2026
0a70ced
Strip mayros- prefix from plugin entry hints to match manifest IDs
ApiliumDevTeam Mar 2, 2026
4fe6887
Fix CI: skip Android playstore without keystore, increase Discord tes…
ApiliumDevTeam Mar 2, 2026
ac9a9a9
Fix plugin ID warnings and CI stability (#6)
ApiliumDevTeam Mar 2, 2026
9577dff
Merge remote-tracking branch 'origin/main'
ApiliumDevTeam Mar 2, 2026
6b53454
Bump version to 0.1.3 and sync extensions (#7)
ApiliumDevTeam Mar 2, 2026
8584422
Merge remote-tracking branch 'origin/main'
ApiliumDevTeam Mar 2, 2026
3cb9588
Exclude .claude/RULES.md from version control
ApiliumDevTeam Mar 3, 2026
edd1511
Fix extension import paths and dependency declarations
ApiliumDevTeam Mar 3, 2026
e5d2008
Replace process.exit with defaultRuntime.exit in CLI modules
ApiliumDevTeam Mar 3, 2026
1c3e6ec
Fix CLI command registration: pass argv explicitly, use allSettled
ApiliumDevTeam Mar 3, 2026
6586dcb
Extract lightweight-commands constants and add primary subcommand guard
ApiliumDevTeam Mar 3, 2026
193d6f3
Fix hardcoded gateway port in SSH tunnel hint
ApiliumDevTeam Mar 3, 2026
0f2e25a
Add resetBannerEmittedForTest helper
ApiliumDevTeam Mar 3, 2026
cbfe9a9
Fix agent-events state cleanup and add missing test reset
ApiliumDevTeam Mar 3, 2026
2809ef7
Replace as any with proper type cast in skill-loader
ApiliumDevTeam Mar 3, 2026
a41fb59
Add injection detection patterns and variant test coverage
ApiliumDevTeam Mar 3, 2026
2886cee
Batch delegation context queries and pre-fetch parent text for dedup
ApiliumDevTeam Mar 3, 2026
32898b1
Fix conflict resolution with companion triples in knowledge fusion
ApiliumDevTeam Mar 3, 2026
75ac488
Fix ACL grant to use system grantor in shared namespace creation
ApiliumDevTeam Mar 3, 2026
44d2bbd
Fix agent-mesh: typed hooks, hardened tools, bounded message log
ApiliumDevTeam Mar 3, 2026
14e9b98
Rewrite semantic-observability hooks to use typed event fields
ApiliumDevTeam Mar 3, 2026
55c0414
Remove unnecessary as Record casts in extension hook handlers
ApiliumDevTeam Mar 3, 2026
d57660c
Add missing bash state reset in commands gating test
ApiliumDevTeam Mar 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,5 @@ USER.md
# Claude Code project instructions (local only)
CLAUDE.md
**/CLAUDE.md

.claude/RULES.md
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:22-bookworm@sha256:cd7bcd2e7a1e6f72052feb023c7f6b722205d3fcab7bbcbd2d1bfdab10b1e935
FROM node:25-bookworm@sha256:c4bfed36421c310d1fbb6dc51faf98065768fbc1c2c1ddd554813ecaa81bb2db

# Install Bun (required for build scripts)
RUN curl -fsSL https://bun.sh/install | bash
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.sandbox
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM debian:bookworm-slim@sha256:98f4b71de414932439ac6ac690d7060df1f27161073c5036a7553723881bffbe
FROM debian:bookworm-slim@sha256:74d56e3931e0d5a1dd51f8c8a2466d21de84a271cd3b5a733b803aa91abf4421

ENV DEBIAN_FRONTEND=noninteractive

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.sandbox-browser
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM debian:bookworm-slim@sha256:98f4b71de414932439ac6ac690d7060df1f27161073c5036a7553723881bffbe
FROM debian:bookworm-slim@sha256:74d56e3931e0d5a1dd51f8c8a2466d21de84a271cd3b5a733b803aa91abf4421

ENV DEBIAN_FRONTEND=noninteractive

Expand Down
114 changes: 66 additions & 48 deletions extensions/agent-mesh/delegation-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,50 +53,56 @@ export class DelegationEngine {
limit: 50,
});

// For each matching memory subject, fetch its triples
// For each matching memory subject, fetch its triples in batches of 5
const relevantTriples: Triple[] = [];
const relatedMemories: string[] = [];
const taskLower = task.toLowerCase();
const taskWords = taskLower.split(/\s+/).filter((w) => w.length > 2);
const CONTEXT_BATCH_SIZE = 5;

for (const match of result.matches) {
const memSubject = match.subject;
const tripleResult = await this.client.listTriples({
subject: memSubject,
limit: 20,
});
for (let i = 0; i < result.matches.length; i += CONTEXT_BATCH_SIZE) {
if (relevantTriples.length >= 100) break;

// Check relevance: does any triple's text contain task keywords?
let isRelevant = false;
for (const t of tripleResult.triples) {
const objStr = String(
typeof t.object === "object" && t.object !== null && "node" in t.object
? t.object.node
: t.object,
).toLowerCase();

for (const word of taskWords) {
if (objStr.includes(word)) {
isRelevant = true;
break;
}
}
if (isRelevant) break;
}
const batch = result.matches.slice(i, i + CONTEXT_BATCH_SIZE);
const batchResults = await Promise.all(
batch.map((match) => this.client.listTriples({ subject: match.subject, limit: 20 })),
);

for (let j = 0; j < batch.length; j++) {
if (relevantTriples.length >= 100) break;

if (isRelevant) {
const memSubject = batch[j].subject;
const tripleResult = batchResults[j];

// Check relevance: does any triple's text contain task keywords?
let isRelevant = false;
for (const t of tripleResult.triples) {
relevantTriples.push(this.tripleToSimple(t));
const objStr = String(
typeof t.object === "object" && t.object !== null && "node" in t.object
? t.object.node
: t.object,
).toLowerCase();

for (const word of taskWords) {
if (objStr.includes(word)) {
isRelevant = true;
break;
}
}
if (isRelevant) break;
}
// Extract memory ID from subject: {ns}:memory:{uuid}
const memPrefix = `${this.ns}:memory:`;
if (memSubject.startsWith(memPrefix)) {
relatedMemories.push(memSubject.slice(memPrefix.length));

if (isRelevant) {
for (const t of tripleResult.triples) {
relevantTriples.push(this.tripleToSimple(t));
}
// Extract memory ID from subject: {ns}:memory:{uuid}
const memPrefix = `${this.ns}:memory:`;
if (memSubject.startsWith(memPrefix)) {
relatedMemories.push(memSubject.slice(memPrefix.length));
}
}
}

// Limit context size
if (relevantTriples.length >= 100) break;
}

return {
Expand Down Expand Up @@ -147,6 +153,14 @@ export class DelegationEngine {
return this.injectedContexts.get(childSessionKey);
}

/**
* Remove injected context for a child session that has ended.
* Prevents memory leaks from accumulated delegation contexts.
*/
removeInjectedContext(childSessionKey: string): void {
this.injectedContexts.delete(childSessionKey);
}

/**
* Merge results from a child agent's namespace back into the parent's namespace.
* Copies new triples from the child run into the parent's knowledge graph,
Expand Down Expand Up @@ -174,7 +188,24 @@ export class DelegationEngine {
limit: 500,
});

const parentSubjects = new Set(parentResult.matches.map((m) => m.subject));
const parentSubjects = parentResult.matches.map((m) => m.subject);

// Pre-fetch all parent text values to avoid N+1 queries during dedup
const parentTextSet = new Set<string>();
const BATCH_SIZE = 5;
for (let i = 0; i < parentSubjects.length; i += BATCH_SIZE) {
const batch = parentSubjects.slice(i, i + BATCH_SIZE);
const results = await Promise.all(
batch.map((subj) => this.client.listTriples({ subject: subj, limit: 20 })),
);
for (const result of results) {
for (const t of result.triples) {
if (t.predicate === `${this.ns}:memory:text`) {
parentTextSet.add(String(t.object));
}
}
}
}

let added = 0;
let skipped = 0;
Expand All @@ -200,20 +231,7 @@ export class DelegationEngine {
}

// Check if parent already has the same text (simple dedup)
let isDuplicate = false;
for (const parentSubj of parentSubjects) {
const parentTriples = await this.client.listTriples({
subject: parentSubj,
limit: 20,
});
for (const pt of parentTriples.triples) {
if (pt.predicate === `${this.ns}:memory:text` && String(pt.object) === textValue) {
isDuplicate = true;
break;
}
}
if (isDuplicate) break;
}
const isDuplicate = parentTextSet.has(textValue);

if (isDuplicate) {
skipped++;
Expand Down
Loading