Skip to content

Commit

Permalink
feature(ai): adds initial integration
Browse files Browse the repository at this point in the history
  • Loading branch information
heapwolf committed May 23, 2024
1 parent 548d71b commit ec79ea9
Show file tree
Hide file tree
Showing 13 changed files with 1,257 additions and 31 deletions.
110 changes: 110 additions & 0 deletions api/ai.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// @ts-check
/**
* @module AI
*
* Provides high level classes for common AI tasks
*
* Example usage:
* ```js
* import { LLM } from 'socket:ai'
* ```
*/
import ipc from './ipc.js'
import gc from './gc.js'
import { EventEmitter } from './events.js'
import { rand64 } from './crypto.js'
import * as exports from './ai.js'

/**
* A class to interact with large language models (using llama.cpp)
* @extends EventEmitter
*/
export class LLM extends EventEmitter {
/**
* Constructs an LLM instance.
* @param {Object} options - The options for initializing the LLM.
* @param {string} options.path - The path to a valid model (.gguf).
* @param {string} options.prompt - The query that guides the model to generate a relevant and coherent responses.
* @param {string} [options.id] - The optional ID for the LLM instance.
* @throws {Error} If the model path is not provided.
*/
constructor (options = {}) {

Check failure on line 31 in api/ai.js

View workflow job for this annotation

GitHub Actions / Lint

Type '{}' is missing the following properties from type '{ path: string; prompt: string; id?: string; }': path, prompt
super()

if (!options.path) {
throw new Error('expected a path to a valid model (.gguf)')
}

this.path = options.path
this.prompt = options.prompt
this.id = options.id || rand64()

const opts = {
id: this.id,
prompt: this.prompt,
path: this.path
}

globalThis.addEventListener('data', ({ detail }) => {

Check failure on line 48 in api/ai.js

View workflow job for this annotation

GitHub Actions / Lint

Property 'detail' does not exist on type 'Event'.
const { err, data, source } = detail.params

if (err && BigInt(err.id) === this.id) {
return this.emit('error', err)
}

if (!data || BigInt(data.id) !== this.id) return

if (source === 'ai.llm.chat') {
if (data.complete) {
return this.emit('end')
}

this.emit('data', data.token)
}
})

const result = ipc.sendSync('ai.llm.create', opts)

if (result.err) {
throw result.err
}
}

/**
* Tell the LLM to stop after the next token.
* @returns {Promise<void>} A promise that resolves when the LLM stops.
*/
async stop () {
return ipc.request('ai.llm.stop', { id: this.id })
}

/**
* Implements `gc.finalizer` for gc'd resource cleanup.
* @param {Object} options - The options for finalizer.
* @returns {gc.Finalizer} The finalizer object.

Check failure on line 84 in api/ai.js

View workflow job for this annotation

GitHub Actions / Lint

Namespace '"/home/runner/work/socket/socket/api/gc".gc' has no exported member 'Finalizer'.
* @ignore
*/
[gc.finalizer] (options) {
return {
args: [this.id, options],
async handle (id) {
if (process.env.DEBUG) {

Check failure on line 91 in api/ai.js

View workflow job for this annotation

GitHub Actions / Lint

Cannot find name 'process'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig.
console.warn('Closing Socket on garbage collection')
}

await ipc.request('ai.llm.destroy', { id }, options)
}
}
}

/**
* Send a message to the chat.
* @param {string} message - The message to send to the chat.
* @returns {Promise<any>} A promise that resolves with the response from the chat.
*/
async chat (message) {
return ipc.request('ai.llm.chat', { id: this.id, message })
}
}

export default exports
1 change: 1 addition & 0 deletions api/commonjs/builtins.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import _async, {
} from '../async.js'

// eslint-disable-next-line
import * as ai from '../ai.js'
import * as application from '../application.js'
import assert from '../assert.js'
import * as buffer from '../buffer.js'
Expand Down
76 changes: 70 additions & 6 deletions bin/build-runtime-library.sh
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ declare sources=(
$(find "$root"/src/ipc/*.cc)
$(find "$root"/src/platform/*.cc)
$(find "$root"/src/serviceworker/*.cc)
"$root/build/llama/common/common.cpp"
"$root/build/llama/common/sampling.cpp"
"$root/build/llama/common/json-schema-to-grammar.cpp"
"$root/build/llama/common/grammar-parser.cpp"
"$root/build/llama/llama.cpp"
"$root/src/window/manager.cc"
"$root/src/window/dialog.cc"
"$root/src/window/hotkey.cc"
Expand All @@ -129,9 +134,11 @@ if [[ "$platform" = "android" ]]; then
sources+=("$root/src/window/android.cc")
elif [[ "$host" = "Darwin" ]]; then
sources+=("$root/src/window/apple.mm")
if (( TARGET_OS_IPHONE)) || (( TARGET_IPHONE_SIMULATOR )); then
cflags=("-sdk" "iphoneos" "$clang")
clang="xcrun"

if (( TARGET_OS_IPHONE)); then
clang="xcrun -sdk iphoneos "$clang""
elif (( TARGET_IPHONE_SIMULATOR )); then
clang="xcrun -sdk iphonesimulator "$clang""
else
sources+=("$root/src/core/process/unix.cc")
fi
Expand All @@ -154,18 +161,62 @@ mkdir -p "$output_directory"

cd "$(dirname "$output_directory")"

sources+=("$output_directory/llama/build-info.cpp")

echo "# building runtime static libary ($arch-$platform)"
for source in "${sources[@]}"; do
declare src_directory="$root/src"

declare object="${source/.cc/$d.o}"
declare object="${object/$src_directory/$output_directory}"
object="${object/.cpp/$d.o}"

declare build_dir="$root/build"

if [[ "$object" =~ ^"$src_directory" ]]; then
object="${object/$src_directory/$output_directory}"
else
object="${object/$build_dir/$output_directory}"
fi

objects+=("$object")
done

if [[ -z "$ignore_header_mtimes" ]]; then
test_headers+="$(find "$root/src"/core/*.hh)"
fi

function generate_llama_build_info () {
build_number="0"
build_commit="unknown"
build_compiler="unknown"
build_target="unknown"

if out=$(git rev-list --count HEAD); then
# git is broken on WSL so we need to strip extra newlines
build_number=$(printf '%s' "$out" | tr -d '\n')
fi

if out=$(git rev-parse --short HEAD); then
build_commit=$(printf '%s' "$out" | tr -d '\n')
fi

if out=$($clang --version | head -1); then
build_compiler=$out
fi

if out=$($clang -dumpmachine); then
build_target=$out
fi

echo "# generating llama build info"
cat > "$output_directory/llama/build-info.cpp" << LLAMA_BUILD_INFO
int LLAMA_BUILD_NUMBER = $build_number;
char const *LLAMA_COMMIT = "$build_commit";
char const *LLAMA_COMPILER = "$build_compiler";
char const *LLAMA_BUILD_TARGET = "$build_target";
LLAMA_BUILD_INFO
}

function main () {
trap onsignal INT TERM
local i=0
Expand All @@ -177,6 +228,8 @@ function main () {
cp -rf "$root/include"/* "$output_directory/include"
rm -f "$output_directory/include/socket/_user-config-bytes.hh"

generate_llama_build_info

for source in "${sources[@]}"; do
if (( ${#pids[@]} > max_concurrency )); then
wait "${pids[0]}" 2>/dev/null
Expand All @@ -185,9 +238,20 @@ function main () {

{
declare src_directory="$root/src"

declare object="${source/.cc/$d.o}"
object="${object/.cpp/$d.o}"

declare header="${source/.cc/.hh}"
declare object="${object/$src_directory/$output_directory}"
header="${header/.cpp/.h}"

declare build_dir="$root/build"

if [[ "$object" =~ ^"$src_directory" ]]; then
object="${object/$src_directory/$output_directory}"
else
object="${object/$build_dir/$output_directory}"
fi

if (( force )) ||
! test -f "$object" ||
Expand All @@ -197,7 +261,7 @@ function main () {
then
mkdir -p "$(dirname "$object")"
echo "# compiling object ($arch-$platform) $(basename "$source")"
quiet "$clang" "${cflags[@]}" -c "$source" -o "$object" || onsignal
quiet $clang "${cflags[@]}" -c "$source" -o "$object" || onsignal
echo "ok - built ${source/$src_directory\//} -> ${object/$output_directory\//} ($arch-$platform)"
fi
} & pids+=($!)
Expand Down
3 changes: 3 additions & 0 deletions bin/cflags.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ cflags+=(
-std=c++2a
-I"$root/include"
-I"$root/build/uv/include"
-I"$root/build"
-I"$root/build/llama"
-I"$root/build/llama/common"
-I"$root/build/include"
-DSOCKET_RUNTIME_BUILD_TIME="$(date '+%s')"
-DSOCKET_RUNTIME_VERSION_HASH=$(git rev-parse --short=8 HEAD)
Expand Down

0 comments on commit ec79ea9

Please sign in to comment.