upgrade run ui
This commit is contained in:
1 parent
bb204f2c6c
commit
a10224d21e
6 files changed
+91
-18
No files matched your search
@@ -1,5 +1,4 @@
|
||||
import re
|
||||
import json
|
||||
import inspect
|
||||
import time
|
||||
import asyncio
|
||||
|
||||
@@ -18,8 +18,10 @@ frontend_path = '../../frontend/dist'
|
||||
|
||||
def encode_json(value):
|
||||
def encode_unknown(value):
|
||||
if value is ToolSpec:
|
||||
if isinstance(value, ToolSpec):
|
||||
return value.to_openai_dict()
|
||||
elif isinstance(value, Stream):
|
||||
return {'streamId': value.id}
|
||||
else:
|
||||
return repr(value)
|
||||
return json.dumps(value, default=encode_unknown)
|
||||
|
||||
+27
-3
@@ -115,6 +115,30 @@ class ToolSpec:
|
||||
def __repr__(self):
|
||||
return f"ToolSpec(name={self.name!r}, params={[p.name for p in self.parameters]})"
|
||||
|
||||
class Tool:
|
||||
"""Base class for tools that implement their logic in a 'run' method.
|
||||
|
||||
Subclasses should override 'run' to provide the tool's functionality.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def run(self, **kwargs):
|
||||
"""Execute the tool. To be overridden by subclasses."""
|
||||
raise NotImplementedError("Tool subclasses must override the 'run' method.")
|
||||
|
||||
def to_spec(self):
|
||||
"""Generate a ToolSpec from this tool instance."""
|
||||
return ToolSpec(
|
||||
name=None, # TODO: Computed from class name, or from class attribute
|
||||
description=None, # TODO: From class doc comment
|
||||
parameters=None, # TODO: Class attribute
|
||||
func=self.run,
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"Tool(name={self.name!r}, params={[p.name for p in self.parameters]})"
|
||||
|
||||
class ToolCall:
|
||||
"""Represents a single tool invocation request emitted by the model.
|
||||
@@ -123,7 +147,7 @@ class ToolCall:
|
||||
id: Unique call identifier (used by OpenAI / llama-cpp protocol).
|
||||
tool_name: Name of the tool to invoke.
|
||||
arguments: Dict of argument name → value.
|
||||
result: String content returned by the tool.
|
||||
result: String content returned by the tool.
|
||||
is_error: Whether the result represents an error.
|
||||
"""
|
||||
|
||||
@@ -136,10 +160,10 @@ class ToolCall:
|
||||
|
||||
def __repr__(self):
|
||||
return f"ToolCall(tool={self.tool_name!r}, args={self.arguments!r})"
|
||||
|
||||
|
||||
def call_message(self):
|
||||
raise Exception("TODO: Llama message for tool call")
|
||||
|
||||
|
||||
def result_message(self):
|
||||
from inference import LlamaMessage
|
||||
return LlamaMessage("tool", self.result)
|
||||
|
||||
@@ -7,14 +7,11 @@ import ContextMenu from './components/main/ContextMenu.vue'
|
||||
|
||||
import * as ui from './ui';
|
||||
import * as backend from './backend';
|
||||
import * as runs from './runs';
|
||||
|
||||
// possible states: loading, login, signup, logged
|
||||
const loginState = ref('loading');
|
||||
|
||||
function triggerAlert () {
|
||||
ui.alert("This is an alert");
|
||||
}
|
||||
|
||||
function handleAuthResult (success) {
|
||||
loginState.value = success ? 'logged' : 'login';
|
||||
}
|
||||
@@ -42,6 +39,11 @@ function signupSubmit (formElem) {
|
||||
backend.signup(username, email, password).then(handleAuthResult);
|
||||
}
|
||||
|
||||
const runsListener = runs.onCreated(run => {
|
||||
console.log("new run", run);
|
||||
});
|
||||
runsListener.allRuns = true; // hack?
|
||||
|
||||
backend.authResult().then(handleAuthResult);
|
||||
</script>
|
||||
|
||||
|
||||
+20
-4
@@ -6,15 +6,18 @@ let unsubscribeRunEvents = null;
|
||||
|
||||
// Event listeners for UI components
|
||||
const listeners = {
|
||||
created: [],
|
||||
runs: [],
|
||||
chats: {},
|
||||
};
|
||||
|
||||
class RunListener {
|
||||
constructor() {
|
||||
constructor() {
|
||||
this.runIds = new Set();
|
||||
this.callbacks = [];
|
||||
this.cancelled = false;
|
||||
this.cancelled = false;
|
||||
|
||||
this.allRuns = false;
|
||||
}
|
||||
|
||||
setIdList(runIds) {
|
||||
@@ -35,7 +38,7 @@ class RunListener {
|
||||
}
|
||||
|
||||
hasRunId(runId) {
|
||||
return this.runIds.has(runId);
|
||||
return this.allRuns || this.runIds.has(runId);
|
||||
}
|
||||
|
||||
emitChange(data) {
|
||||
@@ -56,6 +59,9 @@ function updateRun(event) {
|
||||
if (!run) {
|
||||
run = Object.assign({}, data, {id: runId, events: []});
|
||||
runs.push(run);
|
||||
for (let cb of listeners.created) {
|
||||
cb(run);
|
||||
}
|
||||
} else {
|
||||
console.warn("Created but existing?", run, data);
|
||||
}
|
||||
@@ -71,7 +77,7 @@ function updateRun(event) {
|
||||
}
|
||||
|
||||
if (run) {
|
||||
run.events.push(event);
|
||||
run.events.push({name, runId, data});
|
||||
for (let listener of listeners.runs) {
|
||||
if (listener.hasRunId(runId)) {
|
||||
listener.emitChange(run);
|
||||
@@ -118,6 +124,16 @@ export async function cancelRun(runId) {
|
||||
}
|
||||
|
||||
// Subscribe to runs changes
|
||||
export function onCreated(callback) {
|
||||
listeners.created.push(callback);
|
||||
return () => {
|
||||
const index = listeners.created.indexOf(callback);
|
||||
if (index > -1) {
|
||||
listeners.created.splice(index, 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function addRunListener(callback) {
|
||||
const listener = new RunListener();
|
||||
listener.addCallback(callback);
|
||||
|
||||
@@ -2,10 +2,15 @@
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import TitleBar from '../components/TitleBar.vue';
|
||||
import * as runs from '../runs';
|
||||
import * as backend from '../backend';
|
||||
|
||||
const runList = ref([]);
|
||||
const expandedRunId = ref(null);
|
||||
const runListener = runs.addRunListener(onRunEvent);
|
||||
const expandEvents = ref(false);
|
||||
|
||||
let cancelCreateListener = null;
|
||||
let runListener = runs.addRunListener(onRunEvent);
|
||||
let streamCache = {};
|
||||
|
||||
const toggleRun = (id) => {
|
||||
expandedRunId.value = expandedRunId.value == id ? null : id;
|
||||
@@ -21,7 +26,7 @@
|
||||
};
|
||||
|
||||
function onRunEvent (newRun) {
|
||||
let run = runList.value.findOne(r => r.id == newRun.id);
|
||||
let run = runList.value.find(r => r.id == newRun.id);
|
||||
Object.assign(run, newRun);
|
||||
}
|
||||
|
||||
@@ -30,10 +35,31 @@
|
||||
run => Object.assign({}, run)
|
||||
);
|
||||
runListener.setIdList(runList.value.map(r => r.id));
|
||||
cancelCreateListener = runs.onCreated(run => {
|
||||
runList.value.push(Object.assign({}, run));
|
||||
});
|
||||
});
|
||||
|
||||
function isStreamEvent(event) {
|
||||
return typeof event.data == "object" && event.data.streamId != null;
|
||||
}
|
||||
|
||||
function getStreamRef(event) {
|
||||
let streamId = event.data.streamId;
|
||||
let refObject = streamCache[streamId];
|
||||
if (refObject) return refObject;
|
||||
|
||||
refObject = ref("");
|
||||
let stream = backend.readStream(streamId);
|
||||
stream.on("data", chunk => refObject.value += chunk);
|
||||
|
||||
streamCache[streamId] = refObject;
|
||||
return refObject;
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
runListener.setIdList([]);
|
||||
cancelCreateListener();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -75,9 +101,13 @@
|
||||
<div class="detail-key">Input</div>
|
||||
<pre class="detail-pre">{{ JSON.stringify(run.input, null, 2) }}</pre>
|
||||
</div>
|
||||
<div v-if="run.events && run.events.length > 0" class="detail-row">
|
||||
<div class="detail-key">Events ({{ run.events.length }})</div>
|
||||
<pre class="detail-pre">{{ JSON.stringify(run.events, null, 2) }}</pre>
|
||||
<div class="detail-row" v-for="event in run.events">
|
||||
<div class="detail-key">event: {{ event.name }}</div>
|
||||
<template v-if="isStreamEvent(event)">
|
||||
<div class="detail-value">Stream</div>
|
||||
<pre class="detail-pre">{{ getStreamRef(event) }}</pre>
|
||||
</template>
|
||||
<pre v-else class="detail-pre">{{ JSON.stringify(event.data, null, 2) }}</pre>
|
||||
</div>
|
||||
<div v-if="run.output !== null && run.output !== undefined" class="detail-row">
|
||||
<div class="detail-key">Output</div>
|
||||
|
||||
Reference in new issue
Block a user