Skip to content
This repository was archived by the owner on Mar 25, 2026. It is now read-only.

Commit 44eaee9

Browse files
author
afterrburn
committed
change orchestrator behavior to directly take content to remove path dependency
1 parent a6ae127 commit 44eaee9

4 files changed

Lines changed: 207 additions & 178 deletions

File tree

.github/workflows/@sync-docs.yml

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26,35 +26,52 @@ jobs:
2626
head_commit=${commit_arr[0]}
2727
fi
2828
echo "Comparing $base_commit..$head_commit on main branch"
29-
echo "changed=$(git diff --name-only $base_commit $head_commit -- 'content/**/*.mdx' | xargs)" >> $GITHUB_OUTPUT
30-
echo "removed=$(git diff --name-only --diff-filter=D $base_commit $head_commit -- 'content/**/*.mdx' | xargs)" >> $GITHUB_OUTPUT
31-
32-
- name: Print files being sent to agent
33-
run: |
34-
echo "Changed files: ${{ steps.files.outputs.changed }}"
35-
echo "Removed files: ${{ steps.files.outputs.removed }}"
36-
37-
- name: Trigger Agentuity Sync Agent
38-
run: |
39-
changed_json=$(jq -n --arg files "${{ steps.files.outputs.changed }}" '$files | split(" ") | map(select(length > 0))')
40-
removed_json=$(jq -n --arg files "${{ steps.files.outputs.removed }}" '$files | split(" ") | map(select(length > 0))')
41-
echo "Sending to agent API:"
42-
echo "Changed files JSON: $changed_json"
43-
echo "Removed files JSON: $removed_json"
4429
45-
# Build the complete JSON payload using jq
30+
# Get changed files (relative to content directory)
31+
CHANGED_FILES=$(git diff --name-only $base_commit $head_commit -- 'content/**/*.mdx' | sed 's|^content/||')
32+
REMOVED_FILES=$(git diff --name-only --diff-filter=D $base_commit $head_commit -- 'content/**/*.mdx' | sed 's|^content/||')
33+
34+
echo "Changed files: $CHANGED_FILES"
35+
echo "Removed files: $REMOVED_FILES"
36+
37+
# Build JSON payload with file contents
4638
payload=$(jq -n \
47-
--arg changed "${{ steps.files.outputs.changed }}" \
48-
--arg removed "${{ steps.files.outputs.removed }}" \
49-
'{
50-
changedFiles: ($changed | split(" ") | map(select(length > 0))),
51-
removedFiles: ($removed | split(" ") | map(select(length > 0)))
52-
}')
39+
--arg commit "$head_commit" \
40+
--arg repo "${{ github.repository }}" \
41+
--argjson changed "$(
42+
if [ -n "$CHANGED_FILES" ]; then
43+
for f in $CHANGED_FILES; do
44+
if [ -f "content/$f" ]; then
45+
jq -n \
46+
--arg path "$f" \
47+
--arg content "$(base64 -w0 < "content/$f")" \
48+
'{path: $path, content: $content}'
49+
fi
50+
done | jq -s '.'
51+
else
52+
echo '[]'
53+
fi
54+
)" \
55+
--argjson removed "$(
56+
if [ -n "$REMOVED_FILES" ]; then
57+
printf '%s\n' $REMOVED_FILES | jq -R -s -c 'split("\n") | map(select(length > 0))'
58+
else
59+
echo '[]'
60+
fi
61+
)" \
62+
'{commit: $commit, repo: $repo, changed: $changed, removed: $removed}'
63+
)
5364
54-
echo "Complete JSON payload:"
55-
echo "$payload"
65+
echo "payload<<EOF" >> $GITHUB_OUTPUT
66+
echo "$payload" >> $GITHUB_OUTPUT
67+
echo "EOF" >> $GITHUB_OUTPUT
68+
69+
- name: Trigger Agentuity Sync Agent
70+
run: |
71+
echo "Sending payload to agent:"
72+
echo '${{ steps.files.outputs.payload }}' | jq '.'
5673
5774
curl https://agentuity.ai/webhook/f61d5ce9d6ed85695cc992c55ccdc2a6 \
5875
-X POST \
5976
-H "Content-Type: application/json" \
60-
-d "$payload"
77+
-d '${{ steps.files.outputs.payload }}'

.github/workflows/sync-docs.yml

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,55 @@ jobs:
1717
id: files
1818
run: |
1919
git fetch origin ${{ github.event.before }}
20-
echo "changed=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }} -- 'content/**/*.mdx' | xargs)" >> $GITHUB_OUTPUT
21-
echo "removed=$(git diff --name-only --diff-filter=D ${{ github.event.before }} ${{ github.sha }} -- 'content/**/*.mdx' | xargs)" >> $GITHUB_OUTPUT
20+
21+
# Get changed files (relative to content directory)
22+
CHANGED_FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }} -- 'content/**/*.mdx' | sed 's|^content/||')
23+
REMOVED_FILES=$(git diff --name-only --diff-filter=D ${{ github.event.before }} ${{ github.sha }} -- 'content/**/*.mdx' | sed 's|^content/||')
24+
25+
echo "Changed files: $CHANGED_FILES"
26+
echo "Removed files: $REMOVED_FILES"
27+
28+
# Build JSON payload with file contents
29+
payload=$(jq -n \
30+
--arg commit "${{ github.sha }}" \
31+
--arg repo "${{ github.repository }}" \
32+
--argjson changed "$(
33+
if [ -n "$CHANGED_FILES" ]; then
34+
for f in $CHANGED_FILES; do
35+
if [ -f "content/$f" ]; then
36+
jq -n \
37+
--arg path "$f" \
38+
--arg content "$(base64 -w0 < "content/$f")" \
39+
'{path: $path, content: $content}'
40+
fi
41+
done | jq -s '.'
42+
else
43+
echo '[]'
44+
fi
45+
)" \
46+
--argjson removed "$(
47+
if [ -n "$REMOVED_FILES" ]; then
48+
printf '%s\n' $REMOVED_FILES | jq -R -s -c 'split("\n") | map(select(length > 0))'
49+
else
50+
echo '[]'
51+
fi
52+
)" \
53+
'{commit: $commit, repo: $repo, changed: $changed, removed: $removed}'
54+
)
55+
56+
echo "payload<<EOF" >> $GITHUB_OUTPUT
57+
echo "$payload" >> $GITHUB_OUTPUT
58+
echo "EOF" >> $GITHUB_OUTPUT
2259
2360
- name: Trigger Agentuity Sync Agent
2461
env:
2562
AGENTUITY_TOKEN: ${{ secrets.AGENTUITY_TOKEN }}
2663
run: |
27-
# Convert space-separated lists to JSON arrays
28-
changed_json=$(jq -n --arg files "${{ steps.files.outputs.changed }}" '$files | split(" ") | map(select(length > 0))')
29-
removed_json=$(jq -n --arg files "${{ steps.files.outputs.removed }}" '$files | split(" ") | map(select(length > 0))')
30-
# POST to Agentuity agent webhook
64+
echo "Sending payload to agent:"
65+
echo '${{ steps.files.outputs.payload }}' | jq '.'
66+
3167
curl https://agentuity.ai/webhook/f61d5ce9d6ed85695cc992c55ccdc2a6 \
3268
-X POST \
3369
-H "Authorization: Bearer $AGENTUITY_TOKEN" \
3470
-H "Content-Type: application/json" \
35-
-d '{"changedFiles":'$changed_json', "removedFiles":'$removed_json'}'
71+
-d '${{ steps.files.outputs.payload }}'
Lines changed: 80 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,102 @@
1-
// Node.js built-in modules
2-
import { promises as fs } from 'fs';
3-
import * as path from 'path';
4-
51
import type { AgentContext } from '@agentuity/sdk';
6-
72
import { processDoc } from './docs-processor';
83
import { VECTOR_STORE_NAME } from './config';
94

10-
export const DEFAULT_CONTENT_DIR = path.resolve(__dirname, '../../../../content');
11-
12-
/**
13-
* Checks if a document has changed by comparing its hash.
14-
* @param docPath Absolute path to the .mdx file
15-
* @param newHash Newly computed hash
16-
* @returns true if changed, false if unchanged
17-
*/
18-
export async function hasDocChanged(ctx: AgentContext, docPath: string, newHash: string): Promise<boolean> {
19-
const vectors = await ctx.vector.search(VECTOR_STORE_NAME, {
20-
query: ' ',
21-
limit: 1,
22-
metadata: { path: docPath },
23-
});
24-
if (vectors.length > 0) {
25-
const storedHash = vectors[0]?.metadata?.hash;
26-
return storedHash !== newHash;
27-
}
28-
return true;
5+
interface FilePayload {
6+
path: string;
7+
content: string; // base64-encoded
298
}
309

31-
interface OrchestratorOptions {
32-
changedFiles: string[]; // Absolute file paths
33-
removedFiles: string[]; // Absolute file paths
34-
contentDir?: string; // Defaults to /content
10+
interface SyncPayload {
11+
commit?: string;
12+
repo?: string;
13+
changed: FilePayload[];
14+
removed: string[];
3515
}
3616

3717
interface SyncStats {
38-
processed: number;
39-
deleted: number;
40-
errors: number;
41-
errorFiles: string[];
18+
processed: number;
19+
deleted: number;
20+
errors: number;
21+
errorFiles: string[];
4222
}
4323

4424
/**
45-
* Helper to remove all vectors for a given relative path from the vector store.
25+
* Helper to remove all vectors for a given logical path from the vector store.
4626
*/
47-
async function removeVectorsByRelativePath(ctx: AgentContext, relativePath: string, vectorStoreName: string) {
48-
ctx.logger.info('Removing vectors for path: %s, store: %s, metadata: %o', relativePath, vectorStoreName, { path: relativePath });
49-
const vectors = await ctx.vector.search(vectorStoreName, {
50-
query: ' ',
51-
limit: 1000,
52-
metadata: { path: relativePath },
53-
});
54-
if (vectors.length > 0) {
55-
// Delete vectors one by one to avoid issues with large batches
56-
for (const vector of vectors) {
57-
await ctx.vector.delete(vectorStoreName, vector.key);
58-
}
59-
} else {
60-
ctx.logger.info('No vectors found for path: %s, store: %s, metadata: %o', relativePath, vectorStoreName, { path: relativePath });
27+
async function removeVectorsByPath(ctx: AgentContext, logicalPath: string, vectorStoreName: string) {
28+
ctx.logger.info('Removing vectors for path: %s', logicalPath);
29+
const vectors = await ctx.vector.search(vectorStoreName, {
30+
query: ' ',
31+
limit: 1000,
32+
metadata: { path: logicalPath },
33+
});
34+
35+
if (vectors.length > 0) {
36+
// Delete vectors one by one to avoid issues with large batches
37+
for (const vector of vectors) {
38+
await ctx.vector.delete(vectorStoreName, vector.key);
6139
}
40+
ctx.logger.info('Removed %d vectors for path: %s', vectors.length, logicalPath);
41+
} else {
42+
ctx.logger.info('No vectors found for path: %s', logicalPath);
43+
}
6244
}
6345

64-
export async function syncDocs(ctx: AgentContext, options: OrchestratorOptions): Promise<SyncStats> {
65-
const { changedFiles, removedFiles } = options;
66-
const contentDir = options.contentDir || DEFAULT_CONTENT_DIR;
67-
let processed = 0, deleted = 0, errors = 0;
68-
const errorFiles: string[] = [];
46+
/**
47+
* Process documentation sync from embedded payload - completely filesystem-free
48+
*/
49+
export async function syncDocsFromPayload(ctx: AgentContext, payload: SyncPayload): Promise<SyncStats> {
50+
const { changed, removed } = payload;
51+
let processed = 0, deleted = 0, errors = 0;
52+
const errorFiles: string[] = [];
6953

70-
for (const absolutePath of changedFiles) {
71-
try {
72-
// Compute relative path for metadata and vector store
73-
const relativePath = path.relative(contentDir, absolutePath);
74-
await removeVectorsByRelativePath(ctx, relativePath, VECTOR_STORE_NAME);
75-
const content = await fs.readFile(absolutePath, 'utf-8');
76-
const chunks = await processDoc(content);
77-
for (const chunk of chunks) {
78-
chunk.metadata = {
79-
...chunk.metadata,
80-
path: relativePath,
81-
};
82-
await ctx.vector.upsert(VECTOR_STORE_NAME, chunk);
83-
}
84-
processed++;
85-
} catch (err) {
86-
errors++;
87-
errorFiles.push(absolutePath);
88-
ctx.logger.error('Error processing file %s: %o', absolutePath, err);
89-
}
54+
// Process changed files with embedded content
55+
for (const file of changed) {
56+
try {
57+
const { path: logicalPath, content: base64Content } = file;
58+
59+
// Base64-decode the content
60+
const content = Buffer.from(base64Content, 'base64').toString('utf-8');
61+
62+
// Remove existing vectors for this path
63+
await removeVectorsByPath(ctx, logicalPath, VECTOR_STORE_NAME);
64+
65+
// Process the document content into chunks
66+
const chunks = await processDoc(content);
67+
68+
// Upsert chunks with path metadata
69+
for (const chunk of chunks) {
70+
chunk.metadata = {
71+
...chunk.metadata,
72+
path: logicalPath,
73+
};
74+
await ctx.vector.upsert(VECTOR_STORE_NAME, chunk);
75+
}
76+
77+
processed++;
78+
ctx.logger.info('Successfully processed file: %s (%d chunks)', logicalPath, chunks.length);
79+
} catch (err) {
80+
errors++;
81+
errorFiles.push(file.path);
82+
ctx.logger.error('Error processing file %s: %o', file.path, err);
9083
}
84+
}
9185

92-
for (const absolutePath of removedFiles) {
93-
try {
94-
const relativePath = path.relative(contentDir, absolutePath);
95-
await removeVectorsByRelativePath(ctx, relativePath, VECTOR_STORE_NAME);
96-
deleted++;
97-
} catch (err) {
98-
errors++;
99-
errorFiles.push(absolutePath);
100-
ctx.logger.error('Error deleting file %s: %o', absolutePath, err);
101-
}
86+
// Process removed files
87+
for (const logicalPath of removed) {
88+
try {
89+
await removeVectorsByPath(ctx, logicalPath, VECTOR_STORE_NAME);
90+
deleted++;
91+
ctx.logger.info('Successfully removed file: %s', logicalPath);
92+
} catch (err) {
93+
errors++;
94+
errorFiles.push(logicalPath);
95+
ctx.logger.error('Error deleting file %s: %o', logicalPath, err);
10296
}
97+
}
10398

104-
return { processed, deleted, errors, errorFiles };
99+
const stats = { processed, deleted, errors, errorFiles };
100+
ctx.logger.info('Sync completed: %o', stats);
101+
return stats;
105102
}

0 commit comments

Comments
 (0)