Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
23 changes: 12 additions & 11 deletions packages/ai/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,30 @@ const OPENAI_BATCH_SIZE = 32;
const MAX_CONCURRENCY = 3;
const MAX_RETRIES = 2;

const normalizeText = (value: string) => value.replace(/\s+/g, " ").trim();
export const normalizeText = (value: string) => value.replace(/\s+/g, " ").trim();

const contentHashFor = (value: string) =>
crypto.createHash("sha256").update(normalizeText(value)).digest("hex");
export const contentHashFor = (value: string) =>
crypto.hash("sha256", normalizeText(value));

const seededUnitValue = (seed: string, index: number) => {
const digest = crypto.createHash("sha256").update(`${seed}:${index}`).digest();
export const seededUnitValue = (seed: string, index: number) => {
const digest = crypto.hash("sha256", `${seed}:${index}`, "buffer");
const int = digest.readUInt32BE(0);
return int / 0xffffffff;
};

const syntheticVector = (text: string, dimensions = DEFAULT_EMBEDDING_DIMENSIONS) => {
export const syntheticVector = (text: string, dimensions = DEFAULT_EMBEDDING_DIMENSIONS) => {
const normalized = normalizeText(text);
const hash = contentHashFor(normalized);
const values = Array.from({
length: dimensions
}, (_, index) => {
const centered = seededUnitValue(hash, index) * 2 - 1;
return Number(centered.toFixed(8));
return Math.round(centered * 1e8) / 1e8;
});
return normalizeVector(values);
};

const normalizeVector = (values: number[]) => {
export const normalizeVector = (values: number[]) => {
if (values.length === 0) {
return values;
}
Expand All @@ -43,7 +43,8 @@ const normalizeVector = (values: number[]) => {
return values.map(() => 0);
}

return values.map((value) => Number((value / magnitude).toFixed(8)));
const inverseMagnitude = 1 / magnitude;
return values.map((value) => Math.round(value * inverseMagnitude * 1e8) / 1e8);
};

const toEmbeddingVectorRecord = (
Expand All @@ -52,7 +53,7 @@ const toEmbeddingVectorRecord = (
provider: EmbeddingProvider,
model: string
): EmbeddingVectorRecord => ({
values: normalizeVector(values),
values: provider === "synthetic" ? values : normalizeVector(values),
dimensions: values.length,
provider,
model,
Expand Down Expand Up @@ -127,7 +128,7 @@ const callOpenAiEmbeddings = async (
const data = payload.data ?? [];
return data
.sort((left, right) => (left.index ?? 0) - (right.index ?? 0))
.map((record) => normalizeVector(record.embedding ?? []));
.map((record) => record.embedding ?? []);
};

const embedBatchLive = async (
Expand Down
15 changes: 12 additions & 3 deletions packages/documents/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,22 @@ export class LocalJsonStore<T> {
}

private toPath(key: string) {
const relative = key
const segments = key
.split("/")
.filter(Boolean)
.filter((s) => s && s !== "." && s !== "..");

const relative = segments
.map(sanitizeSegment)
.join(path.sep);

return path.join(this.baseDirectory, `${relative}.json`);
const absoluteBase = path.resolve(this.baseDirectory);
const absoluteResolved = path.resolve(absoluteBase, `${relative}.json`);

if (!absoluteResolved.startsWith(absoluteBase)) {
throw new Error(`Invalid storage key: ${key}`);
}

return absoluteResolved;
}

private readPath(filePath: string) {
Expand Down
47 changes: 43 additions & 4 deletions src/cognitive/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,16 @@ async def run_shell(args: argparse.Namespace):
except ImportError:
pass

service = MissionExecutorService(workspace_root=args.workspace_root, mode=args.mode)
def on_step_update(step_id: str, status: str):
color = "\033[92m" if status == "completed" else "\033[94m"
reset = "\033[0m"
print(f" [{color}{status.upper()}{reset}] {step_id}")

service = MissionExecutorService(
workspace_root=args.workspace_root,
mode=args.mode,
on_step_update=on_step_update,
)
print(f"JeanBot interactive shell ({args.mode} mode)")
print(f"Workspace: {args.workspace_root} ({args.workspace_id})")
print("Type 'exit' or 'quit' to end session. Type 'help' for commands.")
Expand All @@ -65,6 +74,9 @@ async def run_shell(args: argparse.Namespace):
print("Commands:")
print(" help Show this help")
print(" history Show command history")
print(" status Show status of the last mission")
print(" plan Show plan of the last mission")
print(" artifacts List artifacts from the last mission")
print(" exit | quit Exit shell")
print(" <objective> Plan and execute a mission")
print(" refine <feedback> Refine the last mission result with feedback")
Expand All @@ -75,6 +87,34 @@ async def run_shell(args: argparse.Namespace):
print(f" {i:3} {cmd}")
continue

if line.lower() == "status":
if not last_result:
print("No mission has been run yet.")
else:
print(f"Last Mission Status: {last_result.status}")
print(f"Summary: {last_result.verification_summary}")
print(f"Steps: {len(last_result.step_reports)}")
continue

if line.lower() == "plan":
if not last_result:
print("No mission has been run yet.")
else:
print(f"Last Mission: {last_result.mission_id}")
for report in last_result.step_reports:
status_char = "✓" if report.diagnostics and report.diagnostics.failure_class == "none" else "✗"
print(f" {status_char} {report.step_id}: {report.summary[:60]}...")
continue

if line.lower() == "artifacts":
if not last_result:
print("No mission has been run yet.")
else:
print(f"Artifacts ({len(last_result.artifacts)}):")
for artifact in last_result.artifacts:
print(f" - {artifact.title}: {artifact.path}")
continue

if line.lower().startswith("refine "):
if not last_result:
print("Nothing to refine. Run a mission first.")
Expand Down Expand Up @@ -104,13 +144,12 @@ async def run_shell(args: argparse.Namespace):
print(f"Summary: {last_result.verification_summary}")
if last_result.artifacts:
print(f"Artifacts: {len(last_result.artifacts)}")
for artifact in last_result.artifacts:
print(f" - {artifact.title}: {artifact.path}")

except KeyboardInterrupt:
print("\nInterrupt received, type 'exit' to quit.")
except Exception as e:
print(f"\nError: {e}")
print(f"\nError during mission execution: {e}")
print("The shell remains active. You can try a different command or objective.")


async def run_command(args: argparse.Namespace) -> dict:
Expand Down
8 changes: 8 additions & 0 deletions src/cognitive/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,13 +467,15 @@ def __init__(
sub_agent_service: SubAgentService,
file_service: FileService,
policy_service: PolicyService,
on_step_update: Any | None = None,
):
self.runtime = runtime
self.memory_service = memory_service
self.audit_service = audit_service
self.sub_agent_service = sub_agent_service
self.file_service = file_service
self.policy_service = policy_service
self.on_step_update = on_step_update
self.intelligence = MissionExecutionIntelligence()
self.replanner = AdaptiveReplanner()

Expand Down Expand Up @@ -869,6 +871,9 @@ async def _execute_step(
) -> StepOutcome:
step_started_at = utc_now_iso()
step.status = "running"

if self.on_step_update:
self.on_step_update(step.id, "started")

await self.audit_service.record(
"mission.step.started",
Expand Down Expand Up @@ -915,6 +920,9 @@ async def _execute_step(
)

step.status = "completed"

if self.on_step_update:
self.on_step_update(step.id, "completed")

report = StepExecutionRecord(
step_id=sub_agent_result.step_report.step_id,
Expand Down
2 changes: 2 additions & 0 deletions src/cognitive/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class MissionExecutorService:
capability_risk: dict[str, str] = field(default_factory=dict)
failure_policy: dict[str, int] = field(default_factory=dict)
mode: str = "local"
on_step_update: Any | None = None

def build_bundle(self, mission_payload: dict[str, Any]) -> MissionExecutionBundle:
workspace_id = mission_payload.get("workspace_id") or mission_payload.get("workspaceId")
Expand Down Expand Up @@ -112,6 +113,7 @@ def build_bundle(self, mission_payload: dict[str, Any]) -> MissionExecutionBundl
sub_agent_service=subagent_service,
file_service=file_service,
policy_service=policy_service,
on_step_update=self.on_step_update,
)
return MissionExecutionBundle(
record=record,
Expand Down
6 changes: 3 additions & 3 deletions workspace/users/{userId}/.jeanbot/context.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# JeanBot User Context

- Current mission: Smoke test
- Updated at: 2026-03-13T21:07:03.733Z
- Completed steps: Inspect workspace files | Load and update memory context | Run policy and risk review | Decompose objective into steps | Create safety checkpoint | Handle finance-sensitive workflows | Synthesize final mission result | Track status and coordination | Synthesize final mission result | Clarify mission constraints | Produce mission documentation
- Current mission: API mission
- Updated at: 2026-05-28T01:24:35.331Z
- Completed steps: Inspect workspace files | Load and update memory context | Run policy and risk review | Decompose objective into steps | Synthesize final mission result | Track status and coordination | Synthesize final mission result | Clarify mission constraints | Produce mission documentation
- In-progress steps: none
- Upcoming steps: none
Loading