Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 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
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,6 @@
"prettier": "^3.5.3",
"tsx": "^4.19.3",
"typescript": "^5.8.3"
}
},
"packageManager": "[email protected]"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's have this, or my pnpm install alwasy write new field

}
32 changes: 32 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "@athena/core",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./plugin": {
"types": "./dist/plugin.d.ts",
"default": "./dist/plugin.js"
}
},
"scripts": {
"build": "bunchee",
"dev": "bunchee --watch"
},
"repository": {
"type": "git",
"url": "https://github.com/Athena-AI-Lab/athena-core.git"
},
"dependencies": {
"@llama-flow/core": "^0.4.4"
},
"peerDependencies": {
"zod": "^3.25.0"
},
"devDependencies": {
"bunchee": "^6.5.3",
"vitest": "^3.2.4",
"zod": "^3.25.67"
}
}
123 changes: 123 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import {
createWorkflow,
Workflow,
WorkflowEvent,
workflowEvent,
eventSource,
WorkflowContext
} from '@llama-flow/core'
import {
pluginRegisterEvent,
pluginStateAsyncContext,
Plugin,
PluginState,
pluginUnregisterEvent,
AthenaTool
} from './plugin.js'

export type AthenaConfig = {
add (plugin: Plugin): AthenaConfig;
run (): Athena
}

export type Athena = {
get plugins (): ReadonlySet<Plugin>
stop (): Promise<void>
}

const haltEvent = workflowEvent()

export function createAthena (): AthenaConfig {
const coreWorkflow = createWorkflow()
const toolsMap = new Map()
const pluginSet = new Set<Plugin>()
const pluginStateMap = new WeakMap<Plugin, PluginState>()
let sendEvent: WorkflowContext['sendEvent']
// one trick to keep the latest stream
let latest: WorkflowContext['stream']

async function waitFn (handler: (s: WorkflowContext['stream']) => Promise<unknown>) {
const [l, r] = latest.tee()
await handler(l)
latest = r
}

coreWorkflow.handle([pluginRegisterEvent], () => {
pluginSet.values().every((plugin) => {
const pluginState = pluginStateMap.get(plugin)!
const cleanup = pluginStateAsyncContext.run(pluginState,
() => plugin.setup({})
)
if (cleanup) {
pluginState.cleanup = cleanup
}
})
return haltEvent.with()
})

coreWorkflow.handle([pluginUnregisterEvent], () => {
pluginSet.values().every((plugin) => {
const pluginState = pluginStateMap.get(plugin)!
if (pluginState.cleanup) {
pluginState.cleanup()
}
})
return haltEvent.with()
})

const config: AthenaConfig = {
add: (plugin) => {
pluginSet.add(plugin)
const pluginState: PluginState = {
get name() {
return plugin.name
},
epoch: 0,
description: null,
get config () {
// todo: read from yaml file
return {}
},
get tools () {
return toolsMap
},
get athenaContext () {
return {
get stream() {
const [l, r] = latest.tee()
latest = r
return l.filter(
ev =>
eventSource(ev) !== pluginRegisterEvent &&
eventSource(ev) !== pluginUnregisterEvent
);
},
sendEvent,
handle: coreWorkflow.handle,
wait: waitFn
}
}
}
pluginStateMap.set(plugin, pluginState)
return config
},
run: () => {
({ sendEvent, stream: latest } = coreWorkflow.createContext())
sendEvent(pluginRegisterEvent.with())
return {
get tools (): ReadonlyMap<string, AthenaTool> {
return toolsMap
},
get plugins (): ReadonlySet<Plugin> {
return new Set(pluginSet)
},
async stop (): Promise<void> {
await waitFn(s => s.until(haltEvent).toArray())
sendEvent(pluginUnregisterEvent.with())
await waitFn(s => s.until(haltEvent).toArray())
}
}
}
}
return config
}
Loading
Loading