pipeline-sdlc/wwwroot/agent_input.js
yumoqing 0a6baa0d52 feat: AgentInput控件 — TextFiles+UiCode模型选择一体化
- 新增 agent_input.js: bricks.AgentInput extends VBox
  - 内部结构: UiFile + DynamicColumn + UiText + [add_btn | model_selector(UiCode) | filler | submit_btn]
  - options: model_dataurl(模型列表API), model_cwidth, placeholder
  - event inputed: {prompt, add_files, model_id}
  - 自动注册 bricks.Factory.register('AgentInput', ...)
- index.ui/index_cockpit.ui: chat_input 改用 widgettype=AgentInput
- 利用 bricks 的 jsfiles() 机制自动加载 agent_input.js
2026-08-06 13:43:11 +08:00

118 lines
3.7 KiB
JavaScript

// AgentInput — 集成模型选择的输入控件
// options: { model_dataurl, placeholder, url(提交图标), ...TextFiles 原有属性 }
// event: inputed → { prompt, add_files, model_id }
bricks.AgentInput = class extends bricks.VBox {
constructor(opts) {
opts.height = 'auto';
opts.width = '100%';
super(opts);
// file upload
this.inputfilew = new bricks.UiFile({name: 'add_file'});
this.filesbar = new bricks.DynamicColumn({col_cwidth: 10});
this.add_files = [];
this.inputfilew.bind('changed', this.file_added.bind(this));
// text input
this.textw = new bricks.UiText({
name: 'prompt',
placeholder: opts.placeholder || '输入你的需求...'
});
// model selector (UiCode dropdown)
this.model_selector = new bricks.Form({
name: 'model_selector',
cols: 1,
cwidth: opts.model_cwidth || 14,
fields: [{
name: 'model_id',
uitype: 'code',
label: '',
placeholder: '选择模型',
cwidth: 12,
dataurl: opts.model_dataurl || '',
valueField: 'model_id',
textField: 'model_id_text',
params: { valueField: 'model_id', textField: 'model_id_text' }
}]
});
// add file button
var addfilew = new bricks.Svg({
cwidth: 1.5, cheight: 1.5,
url: bricks_resource('imgs/add.svg')
});
addfilew.bind('click', this.add_file.bind(this));
// submit button
var inputw = new bricks.Svg({
cwidth: 1.5, cheight: 1.5,
url: opts.url || bricks_resource('imgs/submit.svg')
});
inputw.bind('click', this.input_finished.bind(this));
// button row: [add_file] [model_selector] [filler] [submit]
var hbox = new bricks.HBox({cheight: 1.5, gap: '4px', alignItems: 'center'});
hbox.add_widget(addfilew);
hbox.add_widget(this.model_selector);
hbox.add_widget(new bricks.VBox({css: 'filler'}));
hbox.add_widget(inputw);
// assemble
this.add_widget(this.inputfilew);
this.add_widget(this.filesbar);
this.add_widget(this.textw);
this.add_widget(hbox);
this.filesbar.hide();
this.inputfilew.hide();
}
input_finished() {
var txt = this.textw.getValue();
if (!txt.prompt || txt.prompt.length < 1) return;
var p = this.params || {};
var mv = this.model_selector.getValue() || {};
var d = Object.assign({}, p, {
add_files: this.add_files,
prompt: txt.prompt,
model_id: mv.model_id || ''
});
this.dispatch('inputed', d);
this.textw.setValue('');
this.add_files = [];
}
file_added(e) {
this.inputfilew.hide();
var file = this.inputfilew.getValue().add_file;
this.inputfilew.reset();
this.add_files.push(file);
this.filesbar.clear_widgets();
var w = new bricks.DeletableLabel({label: file.name});
this.filesbar.add_widget(w);
this.filesbar.show();
w.bind('deleted', this.deleted_file.bind(this, file));
}
deleted_file(file) {
this.add_files = this.add_files.filter(i => i !== file);
if (this.add_files.length === 0) this.filesbar.hide();
}
add_file() {
this.inputfilew.show();
}
getValue() {
var mv = this.model_selector.getValue() || {};
return {
prompt: (this.textw.getValue() || {}).prompt || '',
model_id: mv.model_id || ''
};
}
};
bricks.Factory.register('AgentInput', bricks.AgentInput);