Files
zeekayandGitHub 5b5cf9e9db feat: merge AgentField control plane + SDKs as Hanzo Agents (#1)
Transforms hanzoai/agents from a marketplace config repo into a full
agent orchestration platform by merging the AgentField infrastructure:

- Go control plane (K8s-like agent orchestration, service mesh, DAG workflows)
- Python SDK (FastAPI-based agent framework, LiteLLM, memory, DID/VC)
- TypeScript SDK (@hanzo/agents - Vercel AI SDK, MCP, workflows)
- Go SDK (idiomatic agent builder + client)
- React 19 embedded dashboard (XyFlow DAGs, Recharts, Radix UI)
- Docker/K8s/Helm deployment configs
- Examples: hello world, deep research, RAG, simulation, benchmarks
- Functional test suite across Python/Go/TypeScript

All references rebranded: AgentField β†’ Hanzo Agents
- Module: github.com/hanzoai/agents/control-plane
- Python: hanzo_agents
- TypeScript: @hanzo/agents
- Go: github.com/hanzoai/agents/sdk/go
- Env vars: HANZO_AGENTS_*
- Config: hanzo-agents.yaml

Previous marketplace configs moved to config/ directory.
2026-02-09 18:53:09 -08:00

161 lines
5.4 KiB
TypeScript

import { AgentRouter } from '@hanzo-agents/sdk';
import {
EntityDecisionSchema,
EntityProfileSchema,
FactorGraphSchema,
RunSimulationInputSchema,
ScenarioAnalysisSchema,
SimulationResultSchema,
type EntityDecision,
type EntityProfile,
type FactorGraph,
type RunSimulationInput,
type ScenarioAnalysis,
type SimulationResult
} from '../schemas.js';
export const simulationRouter = new AgentRouter({ prefix: 'simulation' });
const scenarioTargets = {
decompose: 'scenario_decomposeScenario',
factorGraph: 'scenario_generateFactorGraph'
} as const;
const entityTargets = {
batch: 'entity_generateEntityBatch'
} as const;
const decisionTargets = {
batch: 'decision_simulateBatchDecisions'
} as const;
const aggregationTargets = {
aggregate: 'aggregation_aggregateAndAnalyze'
} as const;
simulationRouter.reasoner<RunSimulationInput, SimulationResult>(
'runSimulation',
async (ctx) => {
const scenario = ctx.input.scenario;
const populationSize = ctx.input.populationSize;
const context = ctx.input.context ?? [];
const parallelBatchSize = ctx.input.parallelBatchSize ?? 20;
const explorationRatio = ctx.input.explorationRatio ?? 0.1;
const assertArray = (value: any, label: string) => {
if (!Array.isArray(value)) {
throw new Error(`${label} is not an array: ${JSON.stringify(value)}`);
}
};
const logAndThrow = (stage: string, err: unknown) => {
console.error(`❌ ${stage} failed`, err);
throw err;
};
console.log(`πŸš€ Starting simulation: ${populationSize} entities`);
console.log('\nπŸ“‹ Phase 1: Analyzing scenario...');
const scenarioAnalysis = (await ctx
.call(scenarioTargets.decompose, {
scenario,
context
})
.catch((err) => logAndThrow('Scenario analysis', err))) as ScenarioAnalysis;
if (!scenarioAnalysis?.decisionOptions) {
logAndThrow('Scenario analysis output validation', new Error('decisionOptions missing'));
}
console.log(` Entity type: ${scenarioAnalysis.entityType}`);
console.log(` Decision type: ${scenarioAnalysis.decisionType}`);
console.log(` Options: ${scenarioAnalysis.decisionOptions.join(', ')}`);
console.log('\nπŸ•ΈοΈ Phase 2: Building factor graph...');
const factorGraph = (await ctx
.call(scenarioTargets.factorGraph, {
scenario,
scenarioAnalysis,
context
})
.catch((err) => logAndThrow('Factor graph', err))) as FactorGraph;
if (!factorGraph?.attributes) {
logAndThrow('Factor graph output validation', new Error('attributes missing'));
}
console.log(` Tracking ${Object.keys(factorGraph.attributes).length} attributes`);
console.log(`\nπŸ‘₯ Phase 3: Generating ${populationSize} entities...`);
const entitiesPerBatch = 20;
const allEntities: EntityProfile[] = [];
const numEntityBatches = Math.ceil(populationSize / entitiesPerBatch);
for (let batchNum = 0; batchNum < numEntityBatches; batchNum++) {
const startId = batchNum * entitiesPerBatch;
const batchSize = Math.min(entitiesPerBatch, populationSize - startId);
console.log(` Batch ${batchNum + 1}/${numEntityBatches}: Generating ${batchSize} entities...`);
const batch = (await ctx
.call(entityTargets.batch, {
startId,
batchSize,
scenarioAnalysis,
factorGraph,
explorationRatio
})
.catch((err) => logAndThrow(`Entity batch ${batchNum + 1}`, err))) as EntityProfile[];
assertArray(batch, `entity batch ${batchNum + 1}`);
allEntities.push(...batch);
}
console.log(` βœ… Generated ${allEntities.length} entities`);
console.log('\n🎯 Phase 4: Simulating decisions...');
const allDecisions = (await ctx
.call(decisionTargets.batch, {
entities: allEntities,
scenario,
scenarioAnalysis,
context,
parallelBatchSize
})
.catch((err) => logAndThrow('Decision batch', err))) as EntityDecision[];
assertArray(allDecisions, 'decision batch');
console.log(` βœ… Simulated ${allDecisions.length} decisions`);
console.log('\nπŸ“Š Phase 5: Aggregating results and generating insights...');
const insights = (await ctx
.call(aggregationTargets.aggregate, {
scenario,
scenarioAnalysis,
factorGraph,
entities: allEntities,
decisions: allDecisions,
context
})
.catch((err) => logAndThrow('Aggregation', err))) as SimulationResult['insights'];
const insightsForLog =
insights && typeof insights === 'object'
? insights
: {
outcomeDistribution: {},
keyInsight: 'Fallback insight',
detailedAnalysis: 'Fallback analysis due to invalid model response.',
segmentPatterns: 'Fallback segment patterns.',
causalDrivers: 'Fallback causal drivers.'
};
console.log(`\n🎯 KEY INSIGHT: ${insightsForLog.keyInsight}`);
console.log('\nπŸ“ˆ OUTCOME DISTRIBUTION:');
Object.entries(insightsForLog.outcomeDistribution).forEach(([decision, pct]) => {
console.log(` ${decision}: ${(pct * 100).toFixed(1)}%`);
});
return {
scenario,
context,
populationSize,
scenarioAnalysis,
factorGraph,
entities: allEntities,
decisions: allDecisions,
insights: insightsForLog
};
},
{ inputSchema: RunSimulationInputSchema, outputSchema: SimulationResultSchema }
);