瀏覽代碼

Fix: code debug (#7949)

### What problem does this PR solve?

Fix code component debug issue. #7908.

I delete the additions in #7933, there is no semantic meaning `output`
for `parameters`.

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
tags/v0.19.1
Yongteng Lei 5 月之前
父節點
當前提交
49ff1ca934
沒有連結到貢獻者的電子郵件帳戶。
共有 2 個檔案被更改,包括 62 行新增110 行删除
  1. 47
    105
      agent/component/base.py
  2. 15
    5
      agent/component/code.py

+ 47
- 105
agent/component/base.py 查看文件

# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
from abc import ABC
import builtins import builtins
import json import json
import os
import logging import logging
import os
from abc import ABC
from functools import partial from functools import partial
from typing import Any, Tuple, Union from typing import Any, Tuple, Union




def check(self): def check(self):
raise NotImplementedError("Parameter Object should be checked.") raise NotImplementedError("Parameter Object should be checked.")
def output(self):
return None


@classmethod @classmethod
def _get_or_init_deprecated_params_set(cls): def _get_or_init_deprecated_params_set(cls):
update_from_raw_conf = conf.get(_IS_RAW_CONF, True) update_from_raw_conf = conf.get(_IS_RAW_CONF, True)
if update_from_raw_conf: if update_from_raw_conf:
deprecated_params_set = self._get_or_init_deprecated_params_set() deprecated_params_set = self._get_or_init_deprecated_params_set()
feeded_deprecated_params_set = (
self._get_or_init_feeded_deprecated_params_set()
)
feeded_deprecated_params_set = self._get_or_init_feeded_deprecated_params_set()
user_feeded_params_set = self._get_or_init_user_feeded_params_set() user_feeded_params_set = self._get_or_init_user_feeded_params_set()
setattr(self, _IS_RAW_CONF, False) setattr(self, _IS_RAW_CONF, False)
else: else:
feeded_deprecated_params_set = (
self._get_or_init_feeded_deprecated_params_set(conf)
)
feeded_deprecated_params_set = self._get_or_init_feeded_deprecated_params_set(conf)
user_feeded_params_set = self._get_or_init_user_feeded_params_set(conf) user_feeded_params_set = self._get_or_init_user_feeded_params_set(conf)


def _recursive_update_param(param, config, depth, prefix): def _recursive_update_param(param, config, depth, prefix):


else: else:
# recursive set obj attr # recursive set obj attr
sub_params = _recursive_update_param(
attr, config_value, depth + 1, prefix=f"{prefix}{config_key}."
)
sub_params = _recursive_update_param(attr, config_value, depth + 1, prefix=f"{prefix}{config_key}.")
setattr(param, config_key, sub_params) setattr(param, config_key, sub_params)


if not allow_redundant and redundant_attrs: if not allow_redundant and redundant_attrs:
raise ValueError(
f"cpn `{getattr(self, '_name', type(self))}` has redundant parameters: `{[redundant_attrs]}`"
)
raise ValueError(f"cpn `{getattr(self, '_name', type(self))}` has redundant parameters: `{[redundant_attrs]}`")


return param return param


param_validation_path_prefix = home_dir + "/param_validation/" param_validation_path_prefix = home_dir + "/param_validation/"


param_name = type(self).__name__ param_name = type(self).__name__
param_validation_path = "/".join(
[param_validation_path_prefix, param_name + ".json"]
)
param_validation_path = "/".join([param_validation_path_prefix, param_name + ".json"])


validation_json = None validation_json = None


break break


if not value_legal: if not value_legal:
raise ValueError(
"Plase check runtime conf, {} = {} does not match user-parameter restriction".format(
variable, value
)
)
raise ValueError("Plase check runtime conf, {} = {} does not match user-parameter restriction".format(variable, value))


elif variable in validation_json: elif variable in validation_json:
self._validate_param(attr, validation_json) self._validate_param(attr, validation_json)
@staticmethod @staticmethod
def check_string(param, descr): def check_string(param, descr):
if type(param).__name__ not in ["str"]: if type(param).__name__ not in ["str"]:
raise ValueError(
descr + " {} not supported, should be string type".format(param)
)
raise ValueError(descr + " {} not supported, should be string type".format(param))


@staticmethod @staticmethod
def check_empty(param, descr): def check_empty(param, descr):
if not param: if not param:
raise ValueError(
descr + " does not support empty value."
)
raise ValueError(descr + " does not support empty value.")


@staticmethod @staticmethod
def check_positive_integer(param, descr): def check_positive_integer(param, descr):
if type(param).__name__ not in ["int", "long"] or param <= 0: if type(param).__name__ not in ["int", "long"] or param <= 0:
raise ValueError(
descr + " {} not supported, should be positive integer".format(param)
)
raise ValueError(descr + " {} not supported, should be positive integer".format(param))


@staticmethod @staticmethod
def check_positive_number(param, descr): def check_positive_number(param, descr):
if type(param).__name__ not in ["float", "int", "long"] or param <= 0: if type(param).__name__ not in ["float", "int", "long"] or param <= 0:
raise ValueError(
descr + " {} not supported, should be positive numeric".format(param)
)
raise ValueError(descr + " {} not supported, should be positive numeric".format(param))


@staticmethod @staticmethod
def check_nonnegative_number(param, descr): def check_nonnegative_number(param, descr):
if type(param).__name__ not in ["float", "int", "long"] or param < 0: if type(param).__name__ not in ["float", "int", "long"] or param < 0:
raise ValueError(
descr
+ " {} not supported, should be non-negative numeric".format(param)
)
raise ValueError(descr + " {} not supported, should be non-negative numeric".format(param))


@staticmethod @staticmethod
def check_decimal_float(param, descr): def check_decimal_float(param, descr):
if type(param).__name__ not in ["float", "int"] or param < 0 or param > 1: if type(param).__name__ not in ["float", "int"] or param < 0 or param > 1:
raise ValueError(
descr
+ " {} not supported, should be a float number in range [0, 1]".format(
param
)
)
raise ValueError(descr + " {} not supported, should be a float number in range [0, 1]".format(param))


@staticmethod @staticmethod
def check_boolean(param, descr): def check_boolean(param, descr):
if type(param).__name__ != "bool": if type(param).__name__ != "bool":
raise ValueError(
descr + " {} not supported, should be bool type".format(param)
)
raise ValueError(descr + " {} not supported, should be bool type".format(param))


@staticmethod @staticmethod
def check_open_unit_interval(param, descr): def check_open_unit_interval(param, descr):
if type(param).__name__ not in ["float"] or param <= 0 or param >= 1: if type(param).__name__ not in ["float"] or param <= 0 or param >= 1:
raise ValueError(
descr + " should be a numeric number between 0 and 1 exclusively"
)
raise ValueError(descr + " should be a numeric number between 0 and 1 exclusively")


@staticmethod @staticmethod
def check_valid_value(param, descr, valid_values): def check_valid_value(param, descr, valid_values):
if param not in valid_values: if param not in valid_values:
raise ValueError(
descr
+ " {} is not supported, it should be in {}".format(param, valid_values)
)
raise ValueError(descr + " {} is not supported, it should be in {}".format(param, valid_values))


@staticmethod @staticmethod
def check_defined_type(param, descr, types): def check_defined_type(param, descr, types):
if type(param).__name__ not in types: if type(param).__name__ not in types:
raise ValueError(
descr + " {} not supported, should be one of {}".format(param, types)
)
raise ValueError(descr + " {} not supported, should be one of {}".format(param, types))


@staticmethod @staticmethod
def check_and_change_lower(param, valid_list, descr=""): def check_and_change_lower(param, valid_list, descr=""):
if type(param).__name__ != "str": if type(param).__name__ != "str":
raise ValueError(
descr
+ " {} not supported, should be one of {}".format(param, valid_list)
)
raise ValueError(descr + " {} not supported, should be one of {}".format(param, valid_list))


lower_param = param.lower() lower_param = param.lower()
if lower_param in valid_list: if lower_param in valid_list:
return lower_param return lower_param
else: else:
raise ValueError(
descr
+ " {} not supported, should be one of {}".format(param, valid_list)
)
raise ValueError(descr + " {} not supported, should be one of {}".format(param, valid_list))


@staticmethod @staticmethod
def _greater_equal_than(value, limit): def _greater_equal_than(value, limit):
def _range(value, ranges): def _range(value, ranges):
in_range = False in_range = False
for left_limit, right_limit in ranges: for left_limit, right_limit in ranges:
if (
left_limit - settings.FLOAT_ZERO
<= value
<= right_limit + settings.FLOAT_ZERO
):
if left_limit - settings.FLOAT_ZERO <= value <= right_limit + settings.FLOAT_ZERO:
in_range = True in_range = True
break break




def _warn_deprecated_param(self, param_name, descr): def _warn_deprecated_param(self, param_name, descr):
if self._deprecated_params_set.get(param_name): if self._deprecated_params_set.get(param_name):
logging.warning(
f"{descr} {param_name} is deprecated and ignored in this version."
)
logging.warning(f"{descr} {param_name} is deprecated and ignored in this version.")


def _warn_to_deprecate_param(self, param_name, descr, new_param): def _warn_to_deprecate_param(self, param_name, descr, new_param):
if self._deprecated_params_set.get(param_name): if self._deprecated_params_set.get(param_name):
logging.warning(
f"{descr} {param_name} will be deprecated in future release; "
f"please use {new_param} instead."
)
logging.warning(f"{descr} {param_name} will be deprecated in future release; please use {new_param} instead.")
return True return True
return False return False


"params": {}, "params": {},
"output": {}, "output": {},
"inputs": {} "inputs": {}
}}""".format(self.component_name,
self._param,
json.dumps(json.loads(str(self._param)).get("output", {}), ensure_ascii=False),
json.dumps(json.loads(str(self._param)).get("inputs", []), ensure_ascii=False)
}}""".format(
self.component_name,
self._param,
json.dumps(json.loads(str(self._param)).get("output", {}), ensure_ascii=False),
json.dumps(json.loads(str(self._param)).get("inputs", []), ensure_ascii=False),
) )


def __init__(self, canvas, id, param: ComponentParamBase): def __init__(self, canvas, id, param: ComponentParamBase):
from agent.canvas import Canvas # Local import to avoid cyclic dependency from agent.canvas import Canvas # Local import to avoid cyclic dependency

assert isinstance(canvas, Canvas), "canvas must be an instance of Canvas" assert isinstance(canvas, Canvas), "canvas must be an instance of Canvas"
self._canvas = canvas self._canvas = canvas
self._id = id self._id = id
self._param.check() self._param.check()


def get_dependent_components(self): def get_dependent_components(self):
cpnts = set([para["component_id"].split("@")[0] for para in self._param.query \
if para.get("component_id") \
and para["component_id"].lower().find("answer") < 0 \
and para["component_id"].lower().find("begin") < 0])
cpnts = set(
[
para["component_id"].split("@")[0]
for para in self._param.query
if para.get("component_id") and para["component_id"].lower().find("answer") < 0 and para["component_id"].lower().find("begin") < 0
]
)
return list(cpnts) return list(cpnts)


def run(self, history, **kwargs): def run(self, history, **kwargs):
logging.debug("{}, history: {}, kwargs: {}".format(self, json.dumps(history, ensure_ascii=False),
json.dumps(kwargs, ensure_ascii=False)))
logging.debug("{}, history: {}, kwargs: {}".format(self, json.dumps(history, ensure_ascii=False), json.dumps(kwargs, ensure_ascii=False)))
self._param.debug_inputs = [] self._param.debug_inputs = []
try: try:
res = self._run(history, **kwargs) res = self._run(history, **kwargs)


def set_infor(self, v): def set_infor(self, v):
setattr(self._param, self._param.infor_var_name, v) setattr(self._param, self._param.infor_var_name, v)
def _fetch_outputs_from(self, sources: list[dict[str, Any]]) -> list[pd.DataFrame]: def _fetch_outputs_from(self, sources: list[dict[str, Any]]) -> list[pd.DataFrame]:
outs = [] outs = []
for q in sources: for q in sources:


if q["component_id"].lower().find("answer") == 0: if q["component_id"].lower().find("answer") == 0:
txt = [] txt = []
for r, c in self._canvas.history[::-1][:self._param.message_history_window_size][::-1]:
for r, c in self._canvas.history[::-1][: self._param.message_history_window_size][::-1]:
txt.append(f"{r.upper()}:{c}") txt.append(f"{r.upper()}:{c}")
txt = "\n".join(txt) txt = "\n".join(txt)
outs.append(pd.DataFrame([{"content": txt}])) outs.append(pd.DataFrame([{"content": txt}]))
elif q.get("value"): elif q.get("value"):
outs.append(pd.DataFrame([{"content": q["value"]}])) outs.append(pd.DataFrame([{"content": q["value"]}]))
return outs return outs

def get_input(self): def get_input(self):
if self._param.debug_inputs: if self._param.debug_inputs:
return pd.DataFrame([{"content": v["value"]} for v in self._param.debug_inputs if v.get("value")]) return pd.DataFrame([{"content": v["value"]} for v in self._param.debug_inputs if v.get("value")])
content: str content: str


if len(records) > 1: if len(records) > 1:
content = "\n".join(
[str(d["content"]) for d in records]
)
content = "\n".join([str(d["content"]) for d in records])
else: else:
content = records[0]["content"] content = records[0]["content"]


self._param.inputs.append({
"component_id": records[0].get("component_id"),
"content": content
})
self._param.inputs.append({"component_id": records[0].get("component_id"), "content": content})


if outs: if outs:
df = pd.concat(outs, ignore_index=True) df = pd.concat(outs, ignore_index=True)
if "content" in df: if "content" in df:
df = df.drop_duplicates(subset=['content']).reset_index(drop=True)
df = df.drop_duplicates(subset=["content"]).reset_index(drop=True)
return df return df


upstream_outs = [] upstream_outs = []
o["component_id"] = u o["component_id"] = u
upstream_outs.append(o) upstream_outs.append(o)
continue continue
#if self.component_name.lower()!="answer" and u not in self._canvas.get_component(self._id)["upstream"]: continue
if self.component_name.lower().find("switch") < 0 \
and self.get_component_name(u) in ["relevant", "categorize"]:
# if self.component_name.lower()!="answer" and u not in self._canvas.get_component(self._id)["upstream"]: continue
if self.component_name.lower().find("switch") < 0 and self.get_component_name(u) in ["relevant", "categorize"]:
continue continue
if u.lower().find("answer") >= 0: if u.lower().find("answer") >= 0:
for r, c in self._canvas.history[::-1]: for r, c in self._canvas.history[::-1]:


df = pd.concat(upstream_outs, ignore_index=True) df = pd.concat(upstream_outs, ignore_index=True)
if "content" in df: if "content" in df:
df = df.drop_duplicates(subset=['content']).reset_index(drop=True)
df = df.drop_duplicates(subset=["content"]).reset_index(drop=True)


self._param.inputs = [] self._param.inputs = []
for _, r in df.iterrows(): for _, r in df.iterrows():
return self._canvas.get_component(pid)["obj"] return self._canvas.get_component(pid)["obj"]


def get_upstream(self): def get_upstream(self):
cpn_nms = self._canvas.get_component(self._id)['upstream']
cpn_nms = self._canvas.get_component(self._id)["upstream"]
return cpn_nms return cpn_nms

+ 15
- 5
agent/component/code.py 查看文件

if "value" in param: if "value" in param:
arguments[input["name"]] = param["value"] arguments[input["name"]] = param["value"]
else: else:
cpn = self._canvas.get_component(input["component_id"])["obj"]
if cpn.component_name.lower() == "answer":
refered_component = self._canvas.get_component(input["component_id"])["obj"]
refered_component_name = refered_component.component_name
refered_component_id = refered_component._id
if refered_component_name.lower() == "answer":
arguments[input["name"]] = self._canvas.get_history(1)[0]["content"] arguments[input["name"]] = self._canvas.get_history(1)[0]["content"]
continue continue
_, out = cpn.output(allow_partial=False)
if not out.empty:
arguments[input["name"]] = "\n".join(out["content"])

debug_inputs = self._param.debug_inputs
if debug_inputs:
for param in debug_inputs:
if param["key"] == refered_component_id:
if "value" in param and param["name"] == input["name"]:
arguments[input["name"]] = param["value"]
else:
_, out = refered_component.output(allow_partial=False)
if not out.empty:
arguments[input["name"]] = "\n".join(out["content"])


return self._execute_code( return self._execute_code(
language=self._param.lang, language=self._param.lang,

Loading…
取消
儲存