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 re
|
||||||
import json
|
|
||||||
import inspect
|
import inspect
|
||||||
import time
|
import time
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|||||||
@@ -18,8 +18,10 @@ frontend_path = '../../frontend/dist'
|
|||||||
|
|
||||||
def encode_json(value):
|
def encode_json(value):
|
||||||
def encode_unknown(value):
|
def encode_unknown(value):
|
||||||
if value is ToolSpec:
|
if isinstance(value, ToolSpec):
|
||||||
return value.to_openai_dict()
|
return value.to_openai_dict()
|
||||||
|
elif isinstance(value, Stream):
|
||||||
|
return {'streamId': value.id}
|
||||||
else:
|
else:
|
||||||
return repr(value)
|
return repr(value)
|
||||||
return json.dumps(value, default=encode_unknown)
|
return json.dumps(value, default=encode_unknown)
|
||||||
|
|||||||
+27
-3
@@ -115,6 +115,30 @@ class ToolSpec:
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"ToolSpec(name={self.name!r}, params={[p.name for p in self.parameters]})"
|
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:
|
class ToolCall:
|
||||||
"""Represents a single tool invocation request emitted by the model.
|
"""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).
|
id: Unique call identifier (used by OpenAI / llama-cpp protocol).
|
||||||
tool_name: Name of the tool to invoke.
|
tool_name: Name of the tool to invoke.
|
||||||
arguments: Dict of argument name → value.
|
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.
|
is_error: Whether the result represents an error.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -136,10 +160,10 @@ class ToolCall:
|
|||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"ToolCall(tool={self.tool_name!r}, args={self.arguments!r})"
|
return f"ToolCall(tool={self.tool_name!r}, args={self.arguments!r})"
|
||||||
|
|
||||||
def call_message(self):
|
def call_message(self):
|
||||||
raise Exception("TODO: Llama message for tool call")
|
raise Exception("TODO: Llama message for tool call")
|
||||||
|
|
||||||
def result_message(self):
|
def result_message(self):
|
||||||
from inference import LlamaMessage
|
from inference import LlamaMessage
|
||||||
return LlamaMessage("tool", self.result)
|
return LlamaMessage("tool", self.result)
|
||||||
|
|||||||
@@ -7,14 +7,11 @@ import ContextMenu from './components/main/ContextMenu.vue'
|
|||||||
|
|
||||||
import * as ui from './ui';
|
import * as ui from './ui';
|
||||||
import * as backend from './backend';
|
import * as backend from './backend';
|
||||||
|
import * as runs from './runs';
|
||||||
|
|
||||||
// possible states: loading, login, signup, logged
|
// possible states: loading, login, signup, logged
|
||||||
const loginState = ref('loading');
|
const loginState = ref('loading');
|
||||||
|
|
||||||
function triggerAlert () {
|
|
||||||
ui.alert("This is an alert");
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleAuthResult (success) {
|
function handleAuthResult (success) {
|
||||||
loginState.value = success ? 'logged' : 'login';
|
loginState.value = success ? 'logged' : 'login';
|
||||||
}
|
}
|
||||||
@@ -42,6 +39,11 @@ function signupSubmit (formElem) {
|
|||||||
backend.signup(username, email, password).then(handleAuthResult);
|
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);
|
backend.authResult().then(handleAuthResult);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
+20
-4
@@ -6,15 +6,18 @@ let unsubscribeRunEvents = null;
|
|||||||
|
|
||||||
// Event listeners for UI components
|
// Event listeners for UI components
|
||||||
const listeners = {
|
const listeners = {
|
||||||
|
created: [],
|
||||||
runs: [],
|
runs: [],
|
||||||
chats: {},
|
chats: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
class RunListener {
|
class RunListener {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.runIds = new Set();
|
this.runIds = new Set();
|
||||||
this.callbacks = [];
|
this.callbacks = [];
|
||||||
this.cancelled = false;
|
this.cancelled = false;
|
||||||
|
|
||||||
|
this.allRuns = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
setIdList(runIds) {
|
setIdList(runIds) {
|
||||||
@@ -35,7 +38,7 @@ class RunListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hasRunId(runId) {
|
hasRunId(runId) {
|
||||||
return this.runIds.has(runId);
|
return this.allRuns || this.runIds.has(runId);
|
||||||
}
|
}
|
||||||
|
|
||||||
emitChange(data) {
|
emitChange(data) {
|
||||||
@@ -56,6 +59,9 @@ function updateRun(event) {
|
|||||||
if (!run) {
|
if (!run) {
|
||||||
run = Object.assign({}, data, {id: runId, events: []});
|
run = Object.assign({}, data, {id: runId, events: []});
|
||||||
runs.push(run);
|
runs.push(run);
|
||||||
|
for (let cb of listeners.created) {
|
||||||
|
cb(run);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn("Created but existing?", run, data);
|
console.warn("Created but existing?", run, data);
|
||||||
}
|
}
|
||||||
@@ -71,7 +77,7 @@ function updateRun(event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (run) {
|
if (run) {
|
||||||
run.events.push(event);
|
run.events.push({name, runId, data});
|
||||||
for (let listener of listeners.runs) {
|
for (let listener of listeners.runs) {
|
||||||
if (listener.hasRunId(runId)) {
|
if (listener.hasRunId(runId)) {
|
||||||
listener.emitChange(run);
|
listener.emitChange(run);
|
||||||
@@ -118,6 +124,16 @@ export async function cancelRun(runId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe to runs changes
|
// 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) {
|
export function addRunListener(callback) {
|
||||||
const listener = new RunListener();
|
const listener = new RunListener();
|
||||||
listener.addCallback(callback);
|
listener.addCallback(callback);
|
||||||
|
|||||||
@@ -2,10 +2,15 @@
|
|||||||
import { ref, onMounted, onUnmounted } from 'vue';
|
import { ref, onMounted, onUnmounted } from 'vue';
|
||||||
import TitleBar from '../components/TitleBar.vue';
|
import TitleBar from '../components/TitleBar.vue';
|
||||||
import * as runs from '../runs';
|
import * as runs from '../runs';
|
||||||
|
import * as backend from '../backend';
|
||||||
|
|
||||||
const runList = ref([]);
|
const runList = ref([]);
|
||||||
const expandedRunId = ref(null);
|
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) => {
|
const toggleRun = (id) => {
|
||||||
expandedRunId.value = expandedRunId.value == id ? null : id;
|
expandedRunId.value = expandedRunId.value == id ? null : id;
|
||||||
@@ -21,7 +26,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
function onRunEvent (newRun) {
|
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);
|
Object.assign(run, newRun);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,10 +35,31 @@
|
|||||||
run => Object.assign({}, run)
|
run => Object.assign({}, run)
|
||||||
);
|
);
|
||||||
runListener.setIdList(runList.value.map(r => r.id));
|
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(() => {
|
onUnmounted(() => {
|
||||||
runListener.setIdList([]);
|
runListener.setIdList([]);
|
||||||
|
cancelCreateListener();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -75,9 +101,13 @@
|
|||||||
<div class="detail-key">Input</div>
|
<div class="detail-key">Input</div>
|
||||||
<pre class="detail-pre">{{ JSON.stringify(run.input, null, 2) }}</pre>
|
<pre class="detail-pre">{{ JSON.stringify(run.input, null, 2) }}</pre>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="run.events && run.events.length > 0" class="detail-row">
|
<div class="detail-row" v-for="event in run.events">
|
||||||
<div class="detail-key">Events ({{ run.events.length }})</div>
|
<div class="detail-key">event: {{ event.name }}</div>
|
||||||
<pre class="detail-pre">{{ JSON.stringify(run.events, null, 2) }}</pre>
|
<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>
|
||||||
<div v-if="run.output !== null && run.output !== undefined" class="detail-row">
|
<div v-if="run.output !== null && run.output !== undefined" class="detail-row">
|
||||||
<div class="detail-key">Output</div>
|
<div class="detail-key">Output</div>
|
||||||
|
|||||||
Reference in new issue
Block a user