diff --git a/PROJECT b/PROJECT index 0f57bac66..781991974 100644 --- a/PROJECT +++ b/PROJECT @@ -5,6 +5,7 @@ layout: plugins: manifests.sdk.operatorframework.io/v2: {} scorecard.sdk.operatorframework.io/v2: {} +multigroup: true projectName: arcadia repo: github.com/kubeagi/arcadia resources: @@ -108,4 +109,29 @@ resources: kind: VectorStore path: github.com/kubeagi/arcadia/api/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: kubeagi.k8s.com.cn + group: arcadia + kind: Application + path: github.com/kubeagi/arcadia/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + controller: true + domain: arcadia.kubeagi.k8s.com.cn + group: chain + kind: LLMChain + path: github.com/kubeagi/arcadia/api/v1alpha1/node/chain + version: v1alpha1 +- api: + crdVersion: v1 + controller: true + domain: arcadia.kubeagi.k8s.com.cn + group: prompttemplate + kind: PromptTemplate + path: github.com/kubeagi/arcadia/api/v1alpha1/node/prompttemplate + version: v1alpha1 version: "3" diff --git a/api/v1alpha1/application.go b/api/v1alpha1/application.go new file mode 100644 index 000000000..b5935ad22 --- /dev/null +++ b/api/v1alpha1/application.go @@ -0,0 +1,22 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +const ( + InputNode = "Input" + OutputNode = "Output" +) diff --git a/api/v1alpha1/application_types.go b/api/v1alpha1/application_types.go new file mode 100644 index 000000000..42cb38dae --- /dev/null +++ b/api/v1alpha1/application_types.go @@ -0,0 +1,80 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type NodeConfig struct { + // +kubebuilder:validation:Required + Name string `json:"name,omitempty"` + DisplayName string `json:"displayName,omitempty"` + Description string `json:"description,omitempty"` + Ref *TypedObjectReference `json:"ref,omitempty"` +} + +// ApplicationSpec defines the desired state of Application +type ApplicationSpec struct { + CommonSpec `json:",inline"` + // 开场白,只给客户看的内容,引导客户首次输入 + Prologue string `json:"prologue,omitempty"` + // 节点 + // +kubebuilder:validation:Required + // +kubebuilder:validation:UniqueItems=true + Nodes []Node `json:"nodes"` +} + +type Node struct { + NodeConfig `json:",inline"` + NextNodeName []string `json:"nextNodeName,omitempty"` +} + +// ApplicationStatus defines the observed state of Application +type ApplicationStatus struct { + // ObservedGeneration is the last observed generation. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // ConditionedStatus is the current status + ConditionedStatus `json:",inline"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// Application is the Schema for the applications API +type Application struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ApplicationSpec `json:"spec,omitempty"` + Status ApplicationStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ApplicationList contains a list of Application +type ApplicationList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Application `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Application{}, &ApplicationList{}) +} diff --git a/api/v1alpha1/condition.go b/api/v1alpha1/condition.go index e0f882228..009d5cc4e 100644 --- a/api/v1alpha1/condition.go +++ b/api/v1alpha1/condition.go @@ -213,3 +213,35 @@ func (s *ConditionedStatus) Equal(other *ConditionedStatus) bool { func (s *ConditionedStatus) IsReady() bool { return s.GetCondition(TypeReady).Status == corev1.ConditionTrue } + +func (s *ConditionedStatus) WaitingCompleteCondition() []Condition { + return []Condition{{ + Type: TypeReady, + Status: corev1.ConditionUnknown, + Reason: "Pending", + Message: "Waiting for user to complete", + LastTransitionTime: metav1.Now(), + LastSuccessfulTime: metav1.Now(), + }} +} + +func (s *ConditionedStatus) ErrorCondition(msg string) []Condition { + return []Condition{{ + Type: TypeReady, + Status: corev1.ConditionFalse, + Reason: "Error", + Message: msg, + LastTransitionTime: metav1.Now(), + LastSuccessfulTime: metav1.Now(), + }} +} + +func (s *ConditionedStatus) ReadyCondition() []Condition { + return []Condition{{ + Type: TypeReady, + Status: corev1.ConditionTrue, + LastTransitionTime: metav1.Now(), + LastSuccessfulTime: metav1.Now(), + Message: "Success", + }} +} diff --git a/api/v1alpha1/node/chain/groupversion_info.go b/api/v1alpha1/node/chain/groupversion_info.go new file mode 100644 index 000000000..46a30fe37 --- /dev/null +++ b/api/v1alpha1/node/chain/groupversion_info.go @@ -0,0 +1,41 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1alpha1 contains API Schema definitions for the arcadia v1alpha1 API group +// +kubebuilder:object:generate=true +// +groupName=chain.arcadia.kubeagi.k8s.com.cn +package chain + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +const ( + Group = "chain.arcadia.kubeagi.k8s.com.cn" + Version = "v1alpha1" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: Group, Version: Version} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/api/v1alpha1/node/chain/llmchain_types.go b/api/v1alpha1/node/chain/llmchain_types.go new file mode 100644 index 000000000..9b699c0bf --- /dev/null +++ b/api/v1alpha1/node/chain/llmchain_types.go @@ -0,0 +1,87 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package chain + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/api/v1alpha1/node" +) + +// LLMChainSpec defines the desired state of LLMChain +type LLMChainSpec struct { + v1alpha1.CommonSpec `json:",inline"` + + CommonChainConfig `json:",inline"` + + Input Input `json:"input"` + Output Output `json:"output"` +} + +type Input struct { + LLM node.LLMRef `json:"llm"` + PromptTemplate node.PromptTemplateRef `json:"promptTemplate"` +} +type Output struct { + node.CommonOrInPutOrOutputRef `json:",inline"` +} + +type CommonChainConfig struct { + // 记忆相关参数 + Memory Memory `json:"memory,omitempty"` +} + +type Memory struct { + // 能记住的最大 token 数 + MaxTokenLimit int `json:"maxTokenLimit,omitempty"` +} + +// LLMChainStatus defines the observed state of LLMChain +type LLMChainStatus struct { + // ObservedGeneration is the last observed generation. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // ConditionedStatus is the current status + v1alpha1.ConditionedStatus `json:",inline"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// LLMChain is the Schema for the LLMChains API +type LLMChain struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec LLMChainSpec `json:"spec,omitempty"` + Status LLMChainStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// LLMChainList contains a list of LLMChain +type LLMChainList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []LLMChain `json:"items"` +} + +func init() { + SchemeBuilder.Register(&LLMChain{}, &LLMChainList{}) +} diff --git a/api/v1alpha1/node/chain/zz_generated.deepcopy.go b/api/v1alpha1/node/chain/zz_generated.deepcopy.go new file mode 100644 index 000000000..063ecbcaf --- /dev/null +++ b/api/v1alpha1/node/chain/zz_generated.deepcopy.go @@ -0,0 +1,184 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package chain + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommonChainConfig) DeepCopyInto(out *CommonChainConfig) { + *out = *in + out.Memory = in.Memory +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonChainConfig. +func (in *CommonChainConfig) DeepCopy() *CommonChainConfig { + if in == nil { + return nil + } + out := new(CommonChainConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Input) DeepCopyInto(out *Input) { + *out = *in + out.LLM = in.LLM + out.PromptTemplate = in.PromptTemplate +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Input. +func (in *Input) DeepCopy() *Input { + if in == nil { + return nil + } + out := new(Input) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMChain) DeepCopyInto(out *LLMChain) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMChain. +func (in *LLMChain) DeepCopy() *LLMChain { + if in == nil { + return nil + } + out := new(LLMChain) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *LLMChain) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMChainList) DeepCopyInto(out *LLMChainList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]LLMChain, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMChainList. +func (in *LLMChainList) DeepCopy() *LLMChainList { + if in == nil { + return nil + } + out := new(LLMChainList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *LLMChainList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMChainSpec) DeepCopyInto(out *LLMChainSpec) { + *out = *in + out.CommonSpec = in.CommonSpec + out.CommonChainConfig = in.CommonChainConfig + out.Input = in.Input + in.Output.DeepCopyInto(&out.Output) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMChainSpec. +func (in *LLMChainSpec) DeepCopy() *LLMChainSpec { + if in == nil { + return nil + } + out := new(LLMChainSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMChainStatus) DeepCopyInto(out *LLMChainStatus) { + *out = *in + in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMChainStatus. +func (in *LLMChainStatus) DeepCopy() *LLMChainStatus { + if in == nil { + return nil + } + out := new(LLMChainStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Memory) DeepCopyInto(out *Memory) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Memory. +func (in *Memory) DeepCopy() *Memory { + if in == nil { + return nil + } + out := new(Memory) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Output) DeepCopyInto(out *Output) { + *out = *in + in.CommonOrInPutOrOutputRef.DeepCopyInto(&out.CommonOrInPutOrOutputRef) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Output. +func (in *Output) DeepCopy() *Output { + if in == nil { + return nil + } + out := new(Output) + in.DeepCopyInto(out) + return out +} diff --git a/api/v1alpha1/node/common_type.go b/api/v1alpha1/node/common_type.go new file mode 100644 index 000000000..22c5a64bb --- /dev/null +++ b/api/v1alpha1/node/common_type.go @@ -0,0 +1,59 @@ +package node + +// +kubebuilder:object:generate=true +type CommonRef struct { + // Kind is the type of resource being referenced + // +optional + Kind string `json:"kind,omitempty"` + // Name is the name of resource being referenced + // +optional + Name string `json:"name,omitempty"` +} + +// +kubebuilder:object:generate=true +type ChainRef struct { + CommonRef `json:",inline"` + // +kubebuilder:validation:Enum="chain.arcadia.kubeagi.k8s.com.cn" + // kubebuilder:default="chain.arcadia.kubeagi.k8s.com.cn" + // APIGroup is the group for the resource being referenced. + APIGroup string `json:"apiGroup"` +} + +// +kubebuilder:object:generate=true +type PromptTemplateRef struct { + CommonRef `json:",inline"` + // +kubebuilder:validation:Enum="prompttemplate.arcadia.kubeagi.k8s.com.cn" + // kubebuilder:default="prompttemplate.arcadia.kubeagi.k8s.com.cn" + // APIGroup is the group for the resource being referenced. + APIGroup string `json:"apiGroup"` +} + +// +kubebuilder:object:generate=true +type LLMRef struct { + // +kubebuilder:validation:Enum="LLM" + // kubebuilder:default="LLM" + // Kind is the type of resource being referenced + Kind string `json:"kind"` + // Name is the name of resource being referenced + // +optional + Name string `json:"name,omitempty"` + // +kubebuilder:validation:Enum="arcadia.kubeagi.k8s.com.cn" + // kubebuilder:default="arcadia.kubeagi.k8s.com.cn" + // APIGroup is the group for the resource being referenced. + APIGroup string `json:"apiGroup"` +} + +// +kubebuilder:object:generate=true +type CommonOrInPutOrOutputRef struct { + // APIGroup is the group for the resource being referenced. + // If APIGroup is not specified, the specified Kind must be in the core API group. + // For any other third-party types, APIGroup is required. + APIGroup *string `json:"apiGroup,omitempty"` + // Kind is the type of resource being referenced + //+kubebuilder:default=Input + //+kubebuilder:example=Input;Output + // +optional + Kind string `json:"kind,omitempty"` + // Name is the name of resource being referenced + Name string `json:"name,omitempty"` +} diff --git a/api/v1alpha1/node/prompttemplate/groupversion_info.go b/api/v1alpha1/node/prompttemplate/groupversion_info.go new file mode 100644 index 000000000..c5c35e2a4 --- /dev/null +++ b/api/v1alpha1/node/prompttemplate/groupversion_info.go @@ -0,0 +1,41 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1alpha1 contains API Schema definitions for the arcadia v1alpha1 API group +// +kubebuilder:object:generate=true +// +groupName=prompttemplate.arcadia.kubeagi.k8s.com.cn +package prompttemplate + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +const ( + Group = "prompttemplate.arcadia.kubeagi.k8s.com.cn" + Version = "v1alpha1" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: Group, Version: Version} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/api/v1alpha1/node/prompttemplate/prompttemplate_types.go b/api/v1alpha1/node/prompttemplate/prompttemplate_types.go new file mode 100644 index 000000000..7dd04e1bf --- /dev/null +++ b/api/v1alpha1/node/prompttemplate/prompttemplate_types.go @@ -0,0 +1,84 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package prompttemplate + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/api/v1alpha1/node" +) + +// PromptTemplateSpec defines the desired state of PromptTemplate +type PromptTemplateSpec struct { + v1alpha1.CommonSpec `json:",inline"` + + CommonPromptConfig `json:",inline"` + + Input Input `json:"input,omitempty"` + Output Output `json:"output,omitempty"` +} + +type CommonPromptConfig struct { + // 系统 prompt,支持模版 + SystemMessage string `json:"systemMessage,omitempty"` + // 用户 prompt,支持模版, + UserMessage string `json:"userMessage,omitempty"` +} + +type Input struct { + node.CommonOrInPutOrOutputRef `json:",inline"` +} + +type Output struct { + node.CommonOrInPutOrOutputRef `json:",inline"` +} + +// PromptTemplateStatus defines the observed state of PromptTemplate +type PromptTemplateStatus struct { + // ObservedGeneration is the last observed generation. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // ConditionedStatus is the current status + v1alpha1.ConditionedStatus `json:",inline"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// PromptTemplate is the Schema for the PromptTemplates API +type PromptTemplate struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec PromptTemplateSpec `json:"spec,omitempty"` + Status PromptTemplateStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// PromptTemplateList contains a list of PromptTemplate +type PromptTemplateList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []PromptTemplate `json:"items"` +} + +func init() { + SchemeBuilder.Register(&PromptTemplate{}, &PromptTemplateList{}) +} diff --git a/api/v1alpha1/node/prompttemplate/zz_generated.deepcopy.go b/api/v1alpha1/node/prompttemplate/zz_generated.deepcopy.go new file mode 100644 index 000000000..f37660898 --- /dev/null +++ b/api/v1alpha1/node/prompttemplate/zz_generated.deepcopy.go @@ -0,0 +1,167 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package prompttemplate + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommonPromptConfig) DeepCopyInto(out *CommonPromptConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonPromptConfig. +func (in *CommonPromptConfig) DeepCopy() *CommonPromptConfig { + if in == nil { + return nil + } + out := new(CommonPromptConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Input) DeepCopyInto(out *Input) { + *out = *in + in.CommonOrInPutOrOutputRef.DeepCopyInto(&out.CommonOrInPutOrOutputRef) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Input. +func (in *Input) DeepCopy() *Input { + if in == nil { + return nil + } + out := new(Input) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Output) DeepCopyInto(out *Output) { + *out = *in + in.CommonOrInPutOrOutputRef.DeepCopyInto(&out.CommonOrInPutOrOutputRef) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Output. +func (in *Output) DeepCopy() *Output { + if in == nil { + return nil + } + out := new(Output) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PromptTemplate) DeepCopyInto(out *PromptTemplate) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PromptTemplate. +func (in *PromptTemplate) DeepCopy() *PromptTemplate { + if in == nil { + return nil + } + out := new(PromptTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PromptTemplate) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PromptTemplateList) DeepCopyInto(out *PromptTemplateList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PromptTemplate, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PromptTemplateList. +func (in *PromptTemplateList) DeepCopy() *PromptTemplateList { + if in == nil { + return nil + } + out := new(PromptTemplateList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PromptTemplateList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PromptTemplateSpec) DeepCopyInto(out *PromptTemplateSpec) { + *out = *in + out.CommonSpec = in.CommonSpec + out.CommonPromptConfig = in.CommonPromptConfig + in.Input.DeepCopyInto(&out.Input) + in.Output.DeepCopyInto(&out.Output) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PromptTemplateSpec. +func (in *PromptTemplateSpec) DeepCopy() *PromptTemplateSpec { + if in == nil { + return nil + } + out := new(PromptTemplateSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PromptTemplateStatus) DeepCopyInto(out *PromptTemplateStatus) { + *out = *in + in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PromptTemplateStatus. +func (in *PromptTemplateStatus) DeepCopy() *PromptTemplateStatus { + if in == nil { + return nil + } + out := new(PromptTemplateStatus) + in.DeepCopyInto(out) + return out +} diff --git a/api/v1alpha1/node/zz_generated.deepcopy.go b/api/v1alpha1/node/zz_generated.deepcopy.go new file mode 100644 index 000000000..2759e8459 --- /dev/null +++ b/api/v1alpha1/node/zz_generated.deepcopy.go @@ -0,0 +1,106 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package node + +import () + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ChainRef) DeepCopyInto(out *ChainRef) { + *out = *in + out.CommonRef = in.CommonRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChainRef. +func (in *ChainRef) DeepCopy() *ChainRef { + if in == nil { + return nil + } + out := new(ChainRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommonOrInPutOrOutputRef) DeepCopyInto(out *CommonOrInPutOrOutputRef) { + *out = *in + if in.APIGroup != nil { + in, out := &in.APIGroup, &out.APIGroup + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonOrInPutOrOutputRef. +func (in *CommonOrInPutOrOutputRef) DeepCopy() *CommonOrInPutOrOutputRef { + if in == nil { + return nil + } + out := new(CommonOrInPutOrOutputRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CommonRef) DeepCopyInto(out *CommonRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonRef. +func (in *CommonRef) DeepCopy() *CommonRef { + if in == nil { + return nil + } + out := new(CommonRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LLMRef) DeepCopyInto(out *LLMRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LLMRef. +func (in *LLMRef) DeepCopy() *LLMRef { + if in == nil { + return nil + } + out := new(LLMRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PromptTemplateRef) DeepCopyInto(out *PromptTemplateRef) { + *out = *in + out.CommonRef = in.CommonRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PromptTemplateRef. +func (in *PromptTemplateRef) DeepCopy() *PromptTemplateRef { + if in == nil { + return nil + } + out := new(PromptTemplateRef) + in.DeepCopyInto(out) + return out +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index df723ba7a..bef664053 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -27,6 +27,104 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Application) DeepCopyInto(out *Application) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Application. +func (in *Application) DeepCopy() *Application { + if in == nil { + return nil + } + out := new(Application) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Application) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationList) DeepCopyInto(out *ApplicationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Application, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationList. +func (in *ApplicationList) DeepCopy() *ApplicationList { + if in == nil { + return nil + } + out := new(ApplicationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ApplicationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationSpec) DeepCopyInto(out *ApplicationSpec) { + *out = *in + out.CommonSpec = in.CommonSpec + if in.Nodes != nil { + in, out := &in.Nodes, &out.Nodes + *out = make([]Node, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationSpec. +func (in *ApplicationSpec) DeepCopy() *ApplicationSpec { + if in == nil { + return nil + } + out := new(ApplicationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationStatus) DeepCopyInto(out *ApplicationStatus) { + *out = *in + in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationStatus. +func (in *ApplicationStatus) DeepCopy() *ApplicationStatus { + if in == nil { + return nil + } + out := new(ApplicationStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Chroma) DeepCopyInto(out *Chroma) { *out = *in @@ -885,6 +983,47 @@ func (in *ModelStatus) DeepCopy() *ModelStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Node) DeepCopyInto(out *Node) { + *out = *in + in.NodeConfig.DeepCopyInto(&out.NodeConfig) + if in.NextNodeName != nil { + in, out := &in.NextNodeName, &out.NextNodeName + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Node. +func (in *Node) DeepCopy() *Node { + if in == nil { + return nil + } + out := new(Node) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeConfig) DeepCopyInto(out *NodeConfig) { + *out = *in + if in.Ref != nil { + in, out := &in.Ref, &out.Ref + *out = new(TypedObjectReference) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeConfig. +func (in *NodeConfig) DeepCopy() *NodeConfig { + if in == nil { + return nil + } + out := new(NodeConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OSS) DeepCopyInto(out *OSS) { *out = *in diff --git a/config/crd/bases/arcadia.kubeagi.k8s.com.cn_applications.yaml b/config/crd/bases/arcadia.kubeagi.k8s.com.cn_applications.yaml new file mode 100644 index 000000000..f206b5785 --- /dev/null +++ b/config/crd/bases/arcadia.kubeagi.k8s.com.cn_applications.yaml @@ -0,0 +1,142 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: applications.arcadia.kubeagi.k8s.com.cn +spec: + group: arcadia.kubeagi.k8s.com.cn + names: + kind: Application + listKind: ApplicationList + plural: applications + singular: application + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Application is the Schema for the applications API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ApplicationSpec defines the desired state of Application + properties: + creator: + description: Creator defines datasource creator (AUTO-FILLED by webhook) + type: string + description: + description: Description defines datasource description + type: string + displayName: + description: DisplayName defines datasource display name + type: string + nodes: + description: 节点 + items: + properties: + description: + type: string + displayName: + type: string + name: + type: string + nextNodeName: + items: + type: string + type: array + ref: + properties: + apiGroup: + description: APIGroup is the group for the resource being + referenced. If APIGroup is not specified, the specified + Kind must be in the core API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + namespace: + description: Namespace is the namespace of resource being + referenced + type: string + required: + - kind + - name + type: object + type: object + type: array + uniqueItems: true + prologue: + description: 开场白,只给客户看的内容,引导客户首次输入 + type: string + required: + - nodes + type: object + status: + description: ApplicationStatus defines the observed state of Application + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/arcadia.kubeagi.k8s.com.cn_llmchains.yaml b/config/crd/bases/arcadia.kubeagi.k8s.com.cn_llmchains.yaml new file mode 100644 index 000000000..9491736d7 --- /dev/null +++ b/config/crd/bases/arcadia.kubeagi.k8s.com.cn_llmchains.yaml @@ -0,0 +1,151 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: llmchains.arcadia.kubeagi.k8s.com.cn +spec: + group: arcadia.kubeagi.k8s.com.cn + names: + kind: LLMChain + listKind: LLMChainList + plural: llmchains + singular: llmchain + scope: Namespaced + versions: + - name: chain + schema: + openAPIV3Schema: + description: LLMChain is the Schema for the LLMChains API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: LLMChainSpec defines the desired state of LLMChain + properties: + creator: + description: Creator defines datasource creator (AUTO-FILLED by webhook) + type: string + description: + description: Description defines datasource description + type: string + displayName: + description: DisplayName defines datasource display name + type: string + input: + properties: + llm: + properties: + apiGroup: + description: kubebuilder:default="arcadia.kubeagi.k8s.com.cn" + APIGroup is the group for the resource being referenced. + enum: + - arcadia.kubeagi.k8s.com.cn + type: string + kind: + description: kubebuilder:default="LLM" Kind is the type of + resource being referenced + enum: + - LLM + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - apiGroup + - kind + type: object + promptTemplate: + properties: + apiGroup: + description: kubebuilder:default="prompttemplate.arcadia.kubeagi.k8s.com.cn" + APIGroup is the group for the resource being referenced. + enum: + - prompttemplate.arcadia.kubeagi.k8s.com.cn + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - apiGroup + type: object + required: + - llm + - promptTemplate + type: object + memory: + description: 记忆相关参数 + properties: + maxTokenLimit: + description: 能记住的最大 token 数 + type: integer + type: object + required: + - input + type: object + status: + description: LLMChainStatus defines the observed state of LLMChain + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/arcadia.kubeagi.k8s.com.cn_prompttemplates.yaml b/config/crd/bases/arcadia.kubeagi.k8s.com.cn_prompttemplates.yaml new file mode 100644 index 000000000..11fc9bf14 --- /dev/null +++ b/config/crd/bases/arcadia.kubeagi.k8s.com.cn_prompttemplates.yaml @@ -0,0 +1,136 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: prompttemplates.arcadia.kubeagi.k8s.com.cn +spec: + group: arcadia.kubeagi.k8s.com.cn + names: + kind: PromptTemplate + listKind: PromptTemplateList + plural: prompttemplates + singular: prompttemplate + scope: Namespaced + versions: + - name: prompttemplate + schema: + openAPIV3Schema: + description: PromptTemplate is the Schema for the PromptTemplates API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PromptTemplateSpec defines the desired state of PromptTemplate + properties: + creator: + description: Creator defines datasource creator (AUTO-FILLED by webhook) + type: string + description: + description: Description defines datasource description + type: string + displayName: + description: DisplayName defines datasource display name + type: string + input: + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + default: Input + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + output: + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + default: Input + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + systemMessage: + description: 系统 prompt,支持模版 + type: string + userMessage: + description: 用户 prompt,支持模版, + type: string + type: object + status: + description: PromptTemplateStatus defines the observed state of PromptTemplate + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/chain.arcadia.kubeagi.k8s.com.cn_llmchains.yaml b/config/crd/bases/chain.arcadia.kubeagi.k8s.com.cn_llmchains.yaml new file mode 100644 index 000000000..1c9e6cc33 --- /dev/null +++ b/config/crd/bases/chain.arcadia.kubeagi.k8s.com.cn_llmchains.yaml @@ -0,0 +1,168 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: llmchains.chain.arcadia.kubeagi.k8s.com.cn +spec: + group: chain.arcadia.kubeagi.k8s.com.cn + names: + kind: LLMChain + listKind: LLMChainList + plural: llmchains + singular: llmchain + scope: Namespaced + versions: + - name: chain + schema: + openAPIV3Schema: + description: LLMChain is the Schema for the LLMChains API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: LLMChainSpec defines the desired state of LLMChain + properties: + creator: + description: Creator defines datasource creator (AUTO-FILLED by webhook) + type: string + description: + description: Description defines datasource description + type: string + displayName: + description: DisplayName defines datasource display name + type: string + input: + properties: + llm: + properties: + apiGroup: + description: kubebuilder:default="arcadia.kubeagi.k8s.com.cn" + APIGroup is the group for the resource being referenced. + enum: + - arcadia.kubeagi.k8s.com.cn + type: string + kind: + description: kubebuilder:default="LLM" Kind is the type of + resource being referenced + enum: + - LLM + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - apiGroup + - kind + type: object + promptTemplate: + properties: + apiGroup: + description: kubebuilder:default="prompttemplate.arcadia.kubeagi.k8s.com.cn" + APIGroup is the group for the resource being referenced. + enum: + - prompttemplate.arcadia.kubeagi.k8s.com.cn + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - apiGroup + type: object + required: + - llm + - promptTemplate + type: object + memory: + description: 记忆相关参数 + properties: + maxTokenLimit: + description: 能记住的最大 token 数 + type: integer + type: object + output: + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + default: Input + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + required: + - input + - output + type: object + status: + description: LLMChainStatus defines the observed state of LLMChain + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/prompttemplate.arcadia.kubeagi.k8s.com.cn_prompttemplates.yaml b/config/crd/bases/prompttemplate.arcadia.kubeagi.k8s.com.cn_prompttemplates.yaml new file mode 100644 index 000000000..5016f047e --- /dev/null +++ b/config/crd/bases/prompttemplate.arcadia.kubeagi.k8s.com.cn_prompttemplates.yaml @@ -0,0 +1,136 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: prompttemplates.prompttemplate.arcadia.kubeagi.k8s.com.cn +spec: + group: prompttemplate.arcadia.kubeagi.k8s.com.cn + names: + kind: PromptTemplate + listKind: PromptTemplateList + plural: prompttemplates + singular: prompttemplate + scope: Namespaced + versions: + - name: prompttemplate + schema: + openAPIV3Schema: + description: PromptTemplate is the Schema for the PromptTemplates API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PromptTemplateSpec defines the desired state of PromptTemplate + properties: + creator: + description: Creator defines datasource creator (AUTO-FILLED by webhook) + type: string + description: + description: Description defines datasource description + type: string + displayName: + description: DisplayName defines datasource display name + type: string + input: + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + default: Input + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + output: + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + default: Input + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + systemMessage: + description: 系统 prompt,支持模版 + type: string + userMessage: + description: 用户 prompt,支持模版, + type: string + type: object + status: + description: PromptTemplateStatus defines the observed state of PromptTemplate + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index f9dc429a0..7189f514c 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -13,6 +13,7 @@ resources: - bases/arcadia.kubeagi.k8s.com.cn_models.yaml - bases/arcadia.kubeagi.k8s.com.cn_knowledgebases.yaml - bases/arcadia.kubeagi.k8s.com.cn_vectorstores.yaml +- bases/arcadia.kubeagi.k8s.com.cn_applications.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: @@ -29,6 +30,7 @@ patchesStrategicMerge: #- patches/webhook_in_vectorstores.yaml #- patches/webhook_in_workers.yaml #- patches/webhook_in_models.yaml +#- patches/webhook_in_applications.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. @@ -44,6 +46,7 @@ patchesStrategicMerge: #- patches/cainjection_in_models.yaml #- patches/cainjection_in_knowledgebases.yaml #- patches/cainjection_in_vectorstores.yaml +#- patches/cainjection_in_applications.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/config/crd/patches/cainjection_in_applications.yaml b/config/crd/patches/cainjection_in_applications.yaml new file mode 100644 index 000000000..350815709 --- /dev/null +++ b/config/crd/patches/cainjection_in_applications.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: applications.arcadia.kubeagi.k8s.com.cn diff --git a/config/crd/patches/webhook_in_applications.yaml b/config/crd/patches/webhook_in_applications.yaml new file mode 100644 index 000000000..a97acbbba --- /dev/null +++ b/config/crd/patches/webhook_in_applications.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: applications.arcadia.kubeagi.k8s.com.cn +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/config/rbac/application_editor_role.yaml b/config/rbac/application_editor_role.yaml new file mode 100644 index 000000000..98fe8ae57 --- /dev/null +++ b/config/rbac/application_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit applications. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: application-editor-role +rules: +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications/status + verbs: + - get diff --git a/config/rbac/application_viewer_role.yaml b/config/rbac/application_viewer_role.yaml new file mode 100644 index 000000000..d484d4ca6 --- /dev/null +++ b/config/rbac/application_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view applications. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: application-viewer-role +rules: +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications + verbs: + - get + - list + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications/status + verbs: + - get diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index cf2c1aba3..1b6ddd164 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -71,6 +71,32 @@ rules: - patch - update - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications/finalizers + verbs: + - update +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications/status + verbs: + - get + - patch + - update - apiGroups: - arcadia.kubeagi.k8s.com.cn resources: @@ -372,3 +398,55 @@ rules: - get - patch - update +- apiGroups: + - chain.arcadia.kubeagi.k8s.com.cn + resources: + - LLMChains + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - chain.arcadia.kubeagi.k8s.com.cn + resources: + - LLMChains/finalizers + verbs: + - update +- apiGroups: + - chain.arcadia.kubeagi.k8s.com.cn + resources: + - LLMChains/status + verbs: + - get + - patch + - update +- apiGroups: + - prompttemplate.arcadia.kubeagi.k8s.com.cn + resources: + - PromptTemplates + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - prompttemplate.arcadia.kubeagi.k8s.com.cn + resources: + - PromptTemplates/finalizers + verbs: + - update +- apiGroups: + - prompttemplate.arcadia.kubeagi.k8s.com.cn + resources: + - PromptTemplates/status + verbs: + - get + - patch + - update diff --git a/config/samples/app_llmchain_englishteacher.yaml b/config/samples/app_llmchain_englishteacher.yaml new file mode 100644 index 000000000..1b1f17d93 --- /dev/null +++ b/config/samples/app_llmchain_englishteacher.yaml @@ -0,0 +1,106 @@ +apiVersion: arcadia.kubeagi.k8s.com.cn/v1alpha1 +kind: Application +metadata: + name: base-chat-english-teacher + namespace: arcadia +spec: + displayName: "AI英语老师" + description: "最简单的应用,AI英语老师" + prologue: "Hello, I am English Teacher KubeAGI 🤖" + nodes: + - name: Input + displayName: "用户输入" + description: "用户输入节点,必须" + ref: + kind: Input + nextNodeName: ["prompt-node"] + - name: prompt-node + displayName: "prompt" + description: "设定prompt,template中可以使用{{xx}}来替换变量" + ref: + apiGroup: prompttemplate.arcadia.kubeagi.k8s.com.cn + kind: PromptTemplate + name: base-chat-english-teacher + nextNodeName: ["chain-node"] + - name: llm-node + displayName: "zhipu大模型服务" + description: "设定质谱大模型的访问信息" + ref: + apiGroup: arcadia.kubeagi.k8s.com.cn + kind: LLM + name: base-chat-english-teacher + nextNodeName: ["chain-node"] + - name: chain-node + displayName: "llm chain" + description: "chain是langchain的核心概念,llmChain用于连接prompt和llm" + ref: + apiGroup: chain.arcadia.kubeagi.k8s.com.cn + kind: LLMChain + name: base-chat-english-teacher + nextNodeName: ["Output"] + - name: Output + displayName: "最终输出" + description: "最终输出节点,必须" + ref: + kind: Output +--- +apiVersion: prompttemplate.arcadia.kubeagi.k8s.com.cn/v1alpha1 +kind: PromptTemplate +metadata: + name: base-chat-english-teacher + namespace: arcadia +spec: + displayName: "设定英语老师的prompt" + description: "设定英语老师的prompt,来自https://github.com/f/awesome-chatgpt-prompts?tab=readme-ov-file#act-as-an-english-translator-and-improver" + systemMessage: "I want you to act as an English translator, spelling corrector and improver. I will speak to you in any language, and you will detect the language, translate it and answer in the corrected and improved version of my text, in English. I want you to replace my simplified A0-level words and sentences with more beautiful and elegant, upper level English words and sentences. Keep the meaning same, but make them more literary. I want you to only reply the correction, the improvements and nothing else, do not write explanations." + userMessage: "My sentence is {{question}}" + input: + kind: "Input" + name: "Input" + output: + apiGroup: "arcadia.kubeagi.k8s.com.cn" + kind: "Output" + name: "output-node" +--- +apiVersion: chain.arcadia.kubeagi.k8s.com.cn/v1alpha1 +kind: LLMChain +metadata: + name: base-chat-english-teacher + namespace: arcadia +spec: + displayName: "llm chain" + description: "llm chain" + memory: 20480 + input: + llm: + apiGroup: arcadia.kubeagi.k8s.com.cn + kind: LLM + name: base-chat-english-teacher + promptTemplate: + apiGroup: prompttemplate.arcadia.kubeagi.k8s.com.cn + kind: PromptTemplate + name: base-chat-english-teacher + output: + apiGroup: "arcadia.kubeagi.k8s.com.cn" + kind: "Output" + name: "output-node" +--- +apiVersion: v1 +kind: Secret +metadata: + name: base-chat-english-teacher +type: Opaque +data: + apiKey: "NGZjY2VjZWIxNjY2Y2QxMTgwOGMyMThkNmQ2MTk5NTAuVENYVXZhUUNXRnlJa3hCMw==" # replace this with your API key +--- +apiVersion: arcadia.kubeagi.k8s.com.cn/v1alpha1 +kind: LLM +metadata: + name: base-chat-english-teacher +spec: + type: "zhipuai" + endpoint: + url: "https://open.bigmodel.cn/api/paas/v3/model-api" # replace this with your LLM URL(Zhipuai use predefined url https://open.bigmodel.cn/api/paas/v3/model-api) + authSecret: + kind: secret + name: base-chat-english-teacher diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index 4e72faac0..8ea34078b 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -11,4 +11,5 @@ resources: - arcadia_v1alpha1_vectorstore.yaml - arcadia_v1alpha1_worker.yaml - arcadia_v1alpha1_model.yaml +- arcadia_v1alpha1_application.yaml #+kubebuilder:scaffold:manifestskustomizesamples diff --git a/controllers/application_controller.go b/controllers/application_controller.go new file mode 100644 index 000000000..ef082fcb3 --- /dev/null +++ b/controllers/application_controller.go @@ -0,0 +1,202 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controllers + +import ( + "context" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" +) + +// ApplicationReconciler reconciles an Application object +type ApplicationReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=arcadia.kubeagi.k8s.com.cn,resources=applications,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=arcadia.kubeagi.k8s.com.cn,resources=applications/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=arcadia.kubeagi.k8s.com.cn,resources=applications/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *ApplicationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := ctrl.LoggerFrom(ctx) + log.V(1).Info("Start Application Reconcile") + app := &arcadiav1alpha1.Application{} + if err := r.Get(ctx, req.NamespacedName, app); err != nil { + // There's no need to requeue if the resource no longer exists. + // Otherwise, we'll be requeued implicitly because we return an error. + log.V(1).Info("Failed to get Application") + return ctrl.Result{}, client.IgnoreNotFound(err) + } + log = log.WithValues("Generation", app.GetGeneration(), "ObservedGeneration", app.Status.ObservedGeneration, "creator", app.Spec.Creator) + log.V(1).Info("Get Application instance") + + // Add a finalizer.Then, we can define some operations which should + // occur before the Application to be deleted. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers + if newAdded := controllerutil.AddFinalizer(app, arcadiav1alpha1.Finalizer); newAdded { + log.Info("Try to add Finalizer for Application") + if err := r.Update(ctx, app); err != nil { + log.Error(err, "Failed to update Application to add finalizer, will try again later") + return ctrl.Result{}, err + } + log.Info("Adding Finalizer for Application done") + return ctrl.Result{}, nil + } + + // Check if the Application instance is marked to be deleted, which is + // indicated by the deletion timestamp being set. + if app.GetDeletionTimestamp() != nil && controllerutil.ContainsFinalizer(app, arcadiav1alpha1.Finalizer) { + log.Info("Performing Finalizer Operations for Application before delete CR") + // TODO perform the finalizer operations here, for example: remove vectorstore data? + log.Info("Removing Finalizer for Application after successfully performing the operations") + controllerutil.RemoveFinalizer(app, arcadiav1alpha1.Finalizer) + if err := r.Update(ctx, app); err != nil { + log.Error(err, "Failed to remove finalizer for Application") + return ctrl.Result{}, err + } + log.Info("Remove Application done") + return ctrl.Result{}, nil + } + + app, result, err := r.reconcile(ctx, log, app) + + // Update status after reconciliation. + if updateStatusErr := r.patchStatus(ctx, app); updateStatusErr != nil { + log.Error(updateStatusErr, "unable to update status after reconciliation") + return ctrl.Result{Requeue: true}, updateStatusErr + } + + return result, err +} + +// validate nodes: +// 1. input node must have next node +// 2. output node must not have next node +// 3. input node must only have one +// 4. input node must only have one +// 5. only one node connected to output, and this node type should be chain or agent +// 6. when this node points to output, it can only point to output +// 7. should not have cycle TODO +func (r *ApplicationReconciler) validateNodes(ctx context.Context, log logr.Logger, app *arcadiav1alpha1.Application) (*arcadiav1alpha1.Application, ctrl.Result, error) { + var input, output int + var outputNodeName string + for _, node := range app.Spec.Nodes { + if node.Ref.Kind == arcadiav1alpha1.InputNode { + input++ + if len(node.NextNodeName) == 0 { + r.setCondition(app, app.Status.ErrorCondition("input node needs one or more next nodes")...) + return app, ctrl.Result{}, nil + } + } + if node.Ref.Kind == arcadiav1alpha1.OutputNode { + output++ + outputNodeName = node.Name + if len(node.NextNodeName) != 0 { + r.setCondition(app, app.Status.ErrorCondition("output node should not have next nodes")...) + return app, ctrl.Result{}, nil + } + } + } + if input != 1 { + r.setCondition(app, app.Status.ErrorCondition("need one input node")...) + return app, ctrl.Result{}, nil + } + if output != 1 { + r.setCondition(app, app.Status.ErrorCondition("need one output node")...) + return app, ctrl.Result{}, nil + } + + var toOutput int + var toOutputNodeNext int + for _, node := range app.Spec.Nodes { + for _, n := range node.NextNodeName { + if n == outputNodeName { + toOutput++ + } + group := node.Ref.APIGroup + if group == nil { + r.setCondition(app, app.Status.ErrorCondition("node should have ref.group setting")...) + return app, ctrl.Result{}, nil + } + if *group != "chain.arcadia.kubeagi.k8s.com.cn" && *group != "agent.arcadia.kubeagi.k8s.com.cn" { + r.setCondition(app, app.Status.ErrorCondition("ending node should be chain or agent")...) + return app, ctrl.Result{}, nil + } + toOutputNodeNext = len(node.NextNodeName) + } + } + if toOutput != 1 { + r.setCondition(app, app.Status.ErrorCondition("only one node can output")...) + return app, ctrl.Result{}, nil + } + if toOutputNodeNext != 1 { + r.setCondition(app, app.Status.ErrorCondition("when this node points to output, it can only point to output")...) + return app, ctrl.Result{}, nil + } + + r.setCondition(app, app.Status.ReadyCondition()...) + return app, ctrl.Result{}, nil +} + +func (r *ApplicationReconciler) reconcile(ctx context.Context, log logr.Logger, app *arcadiav1alpha1.Application) (*arcadiav1alpha1.Application, ctrl.Result, error) { + // Observe generation change + if app.Status.ObservedGeneration != app.Generation { + app.Status.ObservedGeneration = app.Generation + r.setCondition(app, app.Status.WaitingCompleteCondition()...) + if updateStatusErr := r.patchStatus(ctx, app); updateStatusErr != nil { + log.Error(updateStatusErr, "unable to update status after generation update") + return app, ctrl.Result{Requeue: true}, updateStatusErr + } + } + if app.Status.IsReady() { + return app, ctrl.Result{}, nil + } + return r.validateNodes(ctx, log, app) +} + +func (r *ApplicationReconciler) patchStatus(ctx context.Context, app *arcadiav1alpha1.Application) error { + latest := &arcadiav1alpha1.Application{} + if err := r.Client.Get(ctx, client.ObjectKeyFromObject(app), latest); err != nil { + return err + } + patch := client.MergeFrom(latest.DeepCopy()) + latest.Status = app.Status + return r.Client.Status().Patch(ctx, latest, patch, client.FieldOwner("application-controller")) +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ApplicationReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&arcadiav1alpha1.Application{}). + Complete(r) +} + +func (r *ApplicationReconciler) setCondition(app *arcadiav1alpha1.Application, condition ...arcadiav1alpha1.Condition) *arcadiav1alpha1.Application { + app.Status.SetConditions(condition...) + return app +} diff --git a/controllers/node/chain/llmchain_controller.go b/controllers/node/chain/llmchain_controller.go new file mode 100644 index 000000000..977b6ac04 --- /dev/null +++ b/controllers/node/chain/llmchain_controller.go @@ -0,0 +1,139 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package chain + +import ( + "context" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + api "github.com/kubeagi/arcadia/api/v1alpha1/node/chain" +) + +// LLMChainReconciler reconciles an LLMChain object +type LLMChainReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=chain.arcadia.kubeagi.k8s.com.cn,resources=LLMChains,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=chain.arcadia.kubeagi.k8s.com.cn,resources=LLMChains/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=chain.arcadia.kubeagi.k8s.com.cn,resources=LLMChains/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *LLMChainReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := ctrl.LoggerFrom(ctx) + log.V(1).Info("Start LLMChain Reconcile") + instance := &api.LLMChain{} + if err := r.Get(ctx, req.NamespacedName, instance); err != nil { + // There's no need to requeue if the resource no longer exists. + // Otherwise, we'll be requeued implicitly because we return an error. + log.V(1).Info("Failed to get LLMChain") + return ctrl.Result{}, client.IgnoreNotFound(err) + } + log = log.WithValues("Generation", instance.GetGeneration(), "ObservedGeneration", instance.Status.ObservedGeneration, "creator", instance.Spec.Creator) + log.V(1).Info("Get LLMChain instance") + + // Add a finalizer.Then, we can define some operations which should + // occur before the LLMChain to be deleted. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers + if newAdded := controllerutil.AddFinalizer(instance, arcadiav1alpha1.Finalizer); newAdded { + log.Info("Try to add Finalizer for LLMChain") + if err := r.Update(ctx, instance); err != nil { + log.Error(err, "Failed to update LLMChain to add finalizer, will try again later") + return ctrl.Result{}, err + } + log.Info("Adding Finalizer for LLMChain done") + return ctrl.Result{}, nil + } + + // Check if the LLMChain instance is marked to be deleted, which is + // indicated by the deletion timestamp being set. + if instance.GetDeletionTimestamp() != nil && controllerutil.ContainsFinalizer(instance, arcadiav1alpha1.Finalizer) { + log.Info("Performing Finalizer Operations for LLMChain before delete CR") + // TODO perform the finalizer operations here, for example: remove vectorstore data? + log.Info("Removing Finalizer for LLMChain after successfully performing the operations") + controllerutil.RemoveFinalizer(instance, arcadiav1alpha1.Finalizer) + if err := r.Update(ctx, instance); err != nil { + log.Error(err, "Failed to remove the finalizer for LLMChain") + return ctrl.Result{}, err + } + log.Info("Remove LLMChain done") + return ctrl.Result{}, nil + } + + instance, result, err := r.reconcile(ctx, log, instance) + + // Update status after reconciliation. + if updateStatusErr := r.patchStatus(ctx, instance); updateStatusErr != nil { + log.Error(updateStatusErr, "unable to update status after reconciliation") + return ctrl.Result{Requeue: true}, updateStatusErr + } + + return result, err +} + +func (r *LLMChainReconciler) reconcile(ctx context.Context, log logr.Logger, instance *api.LLMChain) (*api.LLMChain, ctrl.Result, error) { + // Observe generation change + if instance.Status.ObservedGeneration != instance.Generation { + instance.Status.ObservedGeneration = instance.Generation + r.setCondition(instance, instance.Status.WaitingCompleteCondition()...) + if updateStatusErr := r.patchStatus(ctx, instance); updateStatusErr != nil { + log.Error(updateStatusErr, "unable to update status after generation update") + return instance, ctrl.Result{Requeue: true}, updateStatusErr + } + } + + if instance.Status.IsReady() { + return instance, ctrl.Result{}, nil + } + // Note: should change here + if instance.Spec.Input.LLM.Name != "" && instance.Spec.Input.PromptTemplate.Name != "" { + instance.Status.SetConditions(instance.Status.ReadyCondition()...) + } + return instance, ctrl.Result{}, nil +} + +func (r *LLMChainReconciler) patchStatus(ctx context.Context, instance *api.LLMChain) error { + latest := &api.LLMChain{} + if err := r.Client.Get(ctx, client.ObjectKeyFromObject(instance), latest); err != nil { + return err + } + patch := client.MergeFrom(latest.DeepCopy()) + latest.Status = instance.Status + return r.Client.Status().Patch(ctx, latest, patch, client.FieldOwner("LLMChain-controller")) +} + +// SetupWithManager sets up the controller with the Manager. +func (r *LLMChainReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&api.LLMChain{}). + Complete(r) +} + +func (r *LLMChainReconciler) setCondition(instance *api.LLMChain, condition ...arcadiav1alpha1.Condition) *api.LLMChain { + instance.Status.SetConditions(condition...) + return instance +} diff --git a/controllers/node/prompttemplate/prompttemplate_controller.go b/controllers/node/prompttemplate/prompttemplate_controller.go new file mode 100644 index 000000000..4d23af4d7 --- /dev/null +++ b/controllers/node/prompttemplate/prompttemplate_controller.go @@ -0,0 +1,139 @@ +/* +Copyright 2023 KubeAGI. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package chain + +import ( + "context" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + api "github.com/kubeagi/arcadia/api/v1alpha1/node/prompttemplate" +) + +// PromptTemplateReconciler reconciles an PromptTemplate object +type PromptTemplateReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=prompttemplate.arcadia.kubeagi.k8s.com.cn,resources=PromptTemplates,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=prompttemplate.arcadia.kubeagi.k8s.com.cn,resources=PromptTemplates/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=prompttemplate.arcadia.kubeagi.k8s.com.cn,resources=PromptTemplates/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile +func (r *PromptTemplateReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := ctrl.LoggerFrom(ctx) + log.V(1).Info("Start PromptTemplate Reconcile") + instance := &api.PromptTemplate{} + if err := r.Get(ctx, req.NamespacedName, instance); err != nil { + // There's no need to requeue if the resource no longer exists. + // Otherwise, we'll be requeued implicitly because we return an error. + log.V(1).Info("Failed to get PromptTemplate") + return ctrl.Result{}, client.IgnoreNotFound(err) + } + log = log.WithValues("Generation", instance.GetGeneration(), "ObservedGeneration", instance.Status.ObservedGeneration, "creator", instance.Spec.Creator) + log.V(1).Info("Get PromptTemplate instance") + + // Add a finalizer.Then, we can define some operations which should + // occur before the PromptTemplate to be deleted. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers + if newAdded := controllerutil.AddFinalizer(instance, arcadiav1alpha1.Finalizer); newAdded { + log.Info("Try to add Finalizer for PromptTemplate") + if err := r.Update(ctx, instance); err != nil { + log.Error(err, "Failed to update PromptTemplate to add finalizer, will try again later") + return ctrl.Result{}, err + } + log.Info("Adding Finalizer for PromptTemplate done") + return ctrl.Result{}, nil + } + + // Check if the PromptTemplate instance is marked to be deleted, which is + // indicated by the deletion timestamp being set. + if instance.GetDeletionTimestamp() != nil && controllerutil.ContainsFinalizer(instance, arcadiav1alpha1.Finalizer) { + log.Info("Performing Finalizer Operations for PromptTemplate before delete CR") + // TODO perform the finalizer operations here, for example: remove vectorstore data? + log.Info("Removing Finalizer for PromptTemplate after successfully performing the operations") + controllerutil.RemoveFinalizer(instance, arcadiav1alpha1.Finalizer) + if err := r.Update(ctx, instance); err != nil { + log.Error(err, "Failed to remove the finalizer for PromptTemplate") + return ctrl.Result{}, err + } + log.Info("Remove PromptTemplate done") + return ctrl.Result{}, nil + } + + instance, result, err := r.reconcile(ctx, log, instance) + + // Update status after reconciliation. + if updateStatusErr := r.patchStatus(ctx, instance); updateStatusErr != nil { + log.Error(updateStatusErr, "unable to update status after reconciliation") + return ctrl.Result{Requeue: true}, updateStatusErr + } + + return result, err +} + +func (r *PromptTemplateReconciler) reconcile(ctx context.Context, log logr.Logger, instance *api.PromptTemplate) (*api.PromptTemplate, ctrl.Result, error) { + // Observe generation change + if instance.Status.ObservedGeneration != instance.Generation { + instance.Status.ObservedGeneration = instance.Generation + r.setCondition(instance, instance.Status.WaitingCompleteCondition()...) + if updateStatusErr := r.patchStatus(ctx, instance); updateStatusErr != nil { + log.Error(updateStatusErr, "unable to update status after generation update") + return instance, ctrl.Result{Requeue: true}, updateStatusErr + } + } + + if instance.Status.IsReady() { + return instance, ctrl.Result{}, nil + } + // Note: should change here + if instance.Spec.Input.Name != "" { + instance.Status.SetConditions(instance.Status.ReadyCondition()...) + } + return instance, ctrl.Result{}, nil +} + +func (r *PromptTemplateReconciler) patchStatus(ctx context.Context, instance *api.PromptTemplate) error { + latest := &api.PromptTemplate{} + if err := r.Client.Get(ctx, client.ObjectKeyFromObject(instance), latest); err != nil { + return err + } + patch := client.MergeFrom(latest.DeepCopy()) + latest.Status = instance.Status + return r.Client.Status().Patch(ctx, latest, patch, client.FieldOwner("PromptTemplate-controller")) +} + +// SetupWithManager sets up the controller with the Manager. +func (r *PromptTemplateReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&api.PromptTemplate{}). + Complete(r) +} + +func (r *PromptTemplateReconciler) setCondition(instance *api.PromptTemplate, condition ...arcadiav1alpha1.Condition) *api.PromptTemplate { + instance.Status.SetConditions(condition...) + return instance +} diff --git a/deploy/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_applications.yaml b/deploy/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_applications.yaml new file mode 100644 index 000000000..f206b5785 --- /dev/null +++ b/deploy/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_applications.yaml @@ -0,0 +1,142 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: applications.arcadia.kubeagi.k8s.com.cn +spec: + group: arcadia.kubeagi.k8s.com.cn + names: + kind: Application + listKind: ApplicationList + plural: applications + singular: application + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Application is the Schema for the applications API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ApplicationSpec defines the desired state of Application + properties: + creator: + description: Creator defines datasource creator (AUTO-FILLED by webhook) + type: string + description: + description: Description defines datasource description + type: string + displayName: + description: DisplayName defines datasource display name + type: string + nodes: + description: 节点 + items: + properties: + description: + type: string + displayName: + type: string + name: + type: string + nextNodeName: + items: + type: string + type: array + ref: + properties: + apiGroup: + description: APIGroup is the group for the resource being + referenced. If APIGroup is not specified, the specified + Kind must be in the core API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + namespace: + description: Namespace is the namespace of resource being + referenced + type: string + required: + - kind + - name + type: object + type: object + type: array + uniqueItems: true + prologue: + description: 开场白,只给客户看的内容,引导客户首次输入 + type: string + required: + - nodes + type: object + status: + description: ApplicationStatus defines the observed state of Application + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_llmchains.yaml b/deploy/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_llmchains.yaml new file mode 100644 index 000000000..9491736d7 --- /dev/null +++ b/deploy/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_llmchains.yaml @@ -0,0 +1,151 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: llmchains.arcadia.kubeagi.k8s.com.cn +spec: + group: arcadia.kubeagi.k8s.com.cn + names: + kind: LLMChain + listKind: LLMChainList + plural: llmchains + singular: llmchain + scope: Namespaced + versions: + - name: chain + schema: + openAPIV3Schema: + description: LLMChain is the Schema for the LLMChains API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: LLMChainSpec defines the desired state of LLMChain + properties: + creator: + description: Creator defines datasource creator (AUTO-FILLED by webhook) + type: string + description: + description: Description defines datasource description + type: string + displayName: + description: DisplayName defines datasource display name + type: string + input: + properties: + llm: + properties: + apiGroup: + description: kubebuilder:default="arcadia.kubeagi.k8s.com.cn" + APIGroup is the group for the resource being referenced. + enum: + - arcadia.kubeagi.k8s.com.cn + type: string + kind: + description: kubebuilder:default="LLM" Kind is the type of + resource being referenced + enum: + - LLM + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - apiGroup + - kind + type: object + promptTemplate: + properties: + apiGroup: + description: kubebuilder:default="prompttemplate.arcadia.kubeagi.k8s.com.cn" + APIGroup is the group for the resource being referenced. + enum: + - prompttemplate.arcadia.kubeagi.k8s.com.cn + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - apiGroup + type: object + required: + - llm + - promptTemplate + type: object + memory: + description: 记忆相关参数 + properties: + maxTokenLimit: + description: 能记住的最大 token 数 + type: integer + type: object + required: + - input + type: object + status: + description: LLMChainStatus defines the observed state of LLMChain + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_prompttemplates.yaml b/deploy/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_prompttemplates.yaml new file mode 100644 index 000000000..11fc9bf14 --- /dev/null +++ b/deploy/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_prompttemplates.yaml @@ -0,0 +1,136 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: prompttemplates.arcadia.kubeagi.k8s.com.cn +spec: + group: arcadia.kubeagi.k8s.com.cn + names: + kind: PromptTemplate + listKind: PromptTemplateList + plural: prompttemplates + singular: prompttemplate + scope: Namespaced + versions: + - name: prompttemplate + schema: + openAPIV3Schema: + description: PromptTemplate is the Schema for the PromptTemplates API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PromptTemplateSpec defines the desired state of PromptTemplate + properties: + creator: + description: Creator defines datasource creator (AUTO-FILLED by webhook) + type: string + description: + description: Description defines datasource description + type: string + displayName: + description: DisplayName defines datasource display name + type: string + input: + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + default: Input + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + output: + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + default: Input + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + systemMessage: + description: 系统 prompt,支持模版 + type: string + userMessage: + description: 用户 prompt,支持模版, + type: string + type: object + status: + description: PromptTemplateStatus defines the observed state of PromptTemplate + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/charts/arcadia/crds/chain.arcadia.kubeagi.k8s.com.cn_llmchains.yaml b/deploy/charts/arcadia/crds/chain.arcadia.kubeagi.k8s.com.cn_llmchains.yaml new file mode 100644 index 000000000..1c9e6cc33 --- /dev/null +++ b/deploy/charts/arcadia/crds/chain.arcadia.kubeagi.k8s.com.cn_llmchains.yaml @@ -0,0 +1,168 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: llmchains.chain.arcadia.kubeagi.k8s.com.cn +spec: + group: chain.arcadia.kubeagi.k8s.com.cn + names: + kind: LLMChain + listKind: LLMChainList + plural: llmchains + singular: llmchain + scope: Namespaced + versions: + - name: chain + schema: + openAPIV3Schema: + description: LLMChain is the Schema for the LLMChains API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: LLMChainSpec defines the desired state of LLMChain + properties: + creator: + description: Creator defines datasource creator (AUTO-FILLED by webhook) + type: string + description: + description: Description defines datasource description + type: string + displayName: + description: DisplayName defines datasource display name + type: string + input: + properties: + llm: + properties: + apiGroup: + description: kubebuilder:default="arcadia.kubeagi.k8s.com.cn" + APIGroup is the group for the resource being referenced. + enum: + - arcadia.kubeagi.k8s.com.cn + type: string + kind: + description: kubebuilder:default="LLM" Kind is the type of + resource being referenced + enum: + - LLM + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - apiGroup + - kind + type: object + promptTemplate: + properties: + apiGroup: + description: kubebuilder:default="prompttemplate.arcadia.kubeagi.k8s.com.cn" + APIGroup is the group for the resource being referenced. + enum: + - prompttemplate.arcadia.kubeagi.k8s.com.cn + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - apiGroup + type: object + required: + - llm + - promptTemplate + type: object + memory: + description: 记忆相关参数 + properties: + maxTokenLimit: + description: 能记住的最大 token 数 + type: integer + type: object + output: + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + default: Input + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + required: + - input + - output + type: object + status: + description: LLMChainStatus defines the observed state of LLMChain + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/charts/arcadia/crds/prompttemplate.arcadia.kubeagi.k8s.com.cn_prompttemplates.yaml b/deploy/charts/arcadia/crds/prompttemplate.arcadia.kubeagi.k8s.com.cn_prompttemplates.yaml new file mode 100644 index 000000000..5016f047e --- /dev/null +++ b/deploy/charts/arcadia/crds/prompttemplate.arcadia.kubeagi.k8s.com.cn_prompttemplates.yaml @@ -0,0 +1,136 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: prompttemplates.prompttemplate.arcadia.kubeagi.k8s.com.cn +spec: + group: prompttemplate.arcadia.kubeagi.k8s.com.cn + names: + kind: PromptTemplate + listKind: PromptTemplateList + plural: prompttemplates + singular: prompttemplate + scope: Namespaced + versions: + - name: prompttemplate + schema: + openAPIV3Schema: + description: PromptTemplate is the Schema for the PromptTemplates API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PromptTemplateSpec defines the desired state of PromptTemplate + properties: + creator: + description: Creator defines datasource creator (AUTO-FILLED by webhook) + type: string + description: + description: Description defines datasource description + type: string + displayName: + description: DisplayName defines datasource display name + type: string + input: + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + default: Input + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + output: + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + default: Input + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + type: object + systemMessage: + description: 系统 prompt,支持模版 + type: string + userMessage: + description: 用户 prompt,支持模版, + type: string + type: object + status: + description: PromptTemplateStatus defines the observed state of PromptTemplate + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/charts/arcadia/templates/rbac.yaml b/deploy/charts/arcadia/templates/rbac.yaml index ed502c84f..4a6c3a7d0 100644 --- a/deploy/charts/arcadia/templates/rbac.yaml +++ b/deploy/charts/arcadia/templates/rbac.yaml @@ -88,6 +88,32 @@ rules: - patch - update - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications/finalizers + verbs: + - update +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - applications/status + verbs: + - get + - patch + - update - apiGroups: - arcadia.kubeagi.k8s.com.cn resources: @@ -389,3 +415,55 @@ rules: - get - patch - update +- apiGroups: + - chain.arcadia.kubeagi.k8s.com.cn + resources: + - LLMChains + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - chain.arcadia.kubeagi.k8s.com.cn + resources: + - LLMChains/finalizers + verbs: + - update +- apiGroups: + - chain.arcadia.kubeagi.k8s.com.cn + resources: + - LLMChains/status + verbs: + - get + - patch + - update +- apiGroups: + - prompttemplate.arcadia.kubeagi.k8s.com.cn + resources: + - PromptTemplates + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - prompttemplate.arcadia.kubeagi.k8s.com.cn + resources: + - PromptTemplates/finalizers + verbs: + - update +- apiGroups: + - prompttemplate.arcadia.kubeagi.k8s.com.cn + resources: + - PromptTemplates/status + verbs: + - get + - patch + - update diff --git a/go.mod b/go.mod index d2d617036..63a53b874 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/KawashiroNitori/butcher/v2 v2.0.1 github.com/amikos-tech/chroma-go v0.0.0-20230901221218-d0087270239e github.com/coreos/go-oidc/v3 v3.7.0 + github.com/gin-gonic/gin v1.9.1 github.com/go-logr/logr v1.2.0 github.com/gofiber/fiber/v2 v2.49.1 github.com/golang-jwt/jwt v3.2.2+incompatible @@ -28,18 +29,31 @@ require ( require ( github.com/agnivade/levenshtein v1.1.1 // indirect + github.com/bytedance/sonic v1.9.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/dustin/go-humanize v1.0.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.3 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/leodido/go-urn v1.2.4 // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rs/xid v1.5.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/sosodev/duration v1.1.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/arch v0.3.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/go.sum b/go.sum index a865162bf..d044ea83f 100644 --- a/go.sum +++ b/go.sum @@ -109,6 +109,9 @@ github.com/bjwswang/chroma-go v0.0.0-20231011091545-0041221c9bb3 h1:s82xa+vCYaW2 github.com/bjwswang/chroma-go v0.0.0-20231011091545-0041221c9bb3/go.mod h1:uJwgGN4rBUTMI88Rn68Xia+cTRogOo0/elcPvJYFtBU= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= @@ -116,6 +119,9 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -177,9 +183,15 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -208,8 +220,17 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofiber/fiber/v2 v2.49.1 h1:0W2DRWevSirc8pJl4o8r8QejDR8TV6ZUCawHxwbIdOk= github.com/gofiber/fiber/v2 v2.49.1/go.mod h1:nPUeEBUeeYGgwbDm59Gp7vS8MDyScL6ezr/Np9A13WU= @@ -367,6 +388,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -382,6 +404,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo= github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -460,6 +484,8 @@ github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5h github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -548,12 +574,19 @@ github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= @@ -561,6 +594,10 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/langchaingo v0.0.0-20231017212009-949349d5ef9c h1:CgTequ9Xl8+3sOsjXeKj2g2jH+P3QLNXtATONeDMziE= github.com/tmc/langchaingo v0.0.0-20231017212009-949349d5ef9c/go.mod h1:SiwyRS7sBSSi6f3NB4dKENw69X6br/wZ2WRkM+8pZWk= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.49.0 h1:9FdvCpmxB74LH4dPb7IJ1cOSsluR07XG3I1txXWwJpE= @@ -635,6 +672,9 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -1117,6 +1157,7 @@ k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/ k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw= diff --git a/graphql-server/go-server/main.go b/graphql-server/go-server/main.go index 5a739abca..c70386cea 100644 --- a/graphql-server/go-server/main.go +++ b/graphql-server/go-server/main.go @@ -27,13 +27,15 @@ import ( "github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/playground" + "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/chat" + "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/dataprocessing" + "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/minio" "k8s.io/klog/v2" + "github.com/gin-gonic/gin" "github.com/kubeagi/arcadia/graphql-server/go-server/graph/generated" "github.com/kubeagi/arcadia/graphql-server/go-server/graph/impl" "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/auth" - "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/dataprocessing" - "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/minio" "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/oidc" _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" @@ -68,6 +70,25 @@ func main() { // initialize dataprocessing dataprocessing.Init(*dataProcessingURL) + r := gin.Default() + r.POST("/bff", graphqlHandler()) + if *enablePlayground { + r.GET("/", playgroundHandler()) + } + r.POST("/chat", chatHandler()) + + // todo refactor these handlers like others + http.HandleFunc("/minio/get_chunks", minio.GetSuccessChunks) + http.HandleFunc("/minio/new_multipart", minio.NewMultipart) + http.HandleFunc("/minio/get_multipart_url", minio.GetMultipartUploadURL) + http.HandleFunc("/minio/complete_multipart", minio.CompleteMultipart) + http.HandleFunc("/minio/update_chunk", minio.UpdateMultipart) + + klog.Infof("listening server on port: %d", *port) + log.Fatal(r.Run(fmt.Sprintf("%s:%d", *host, *port))) +} + +func graphqlHandler() gin.HandlerFunc { srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &impl.Resolver{}})) srv.AroundFields(func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { rc := graphql.GetFieldContext(ctx) @@ -76,29 +97,40 @@ func main() { klog.Infoln("Left", rc.Object, rc.Field.Name, "=>", res, err) return res, err }) + serveHTTP := srv.ServeHTTP + if *enableOIDC { + serveHTTP = auth.AuthInterceptor(oidc.Verifier, srv.ServeHTTP) + } + return func(c *gin.Context) { + serveHTTP(c.Writer, c.Request) + } +} - if *enablePlayground { - endpoint := "/bff" - if *playgroundEndpointPrefix != "" { - if prefix := strings.TrimPrefix(strings.TrimSuffix(*playgroundEndpointPrefix, "/"), "/"); prefix != "" { - endpoint = fmt.Sprintf("/%s%s", prefix, endpoint) - } +func playgroundHandler() gin.HandlerFunc { + endpoint := "/bff" + if *playgroundEndpointPrefix != "" { + if prefix := strings.TrimPrefix(strings.TrimSuffix(*playgroundEndpointPrefix, "/"), "/"); prefix != "" { + endpoint = fmt.Sprintf("/%s%s", prefix, endpoint) } - http.Handle("/", playground.Handler("Arcadia-Graphql-Server", endpoint)) } - - if *enableOIDC { - http.Handle("/bff", auth.AuthInterceptor(oidc.Verifier, srv.ServeHTTP)) - } else { - http.Handle("/bff", srv) + h := playground.Handler("Arcadia-Graphql-Server", endpoint) + return func(c *gin.Context) { + h.ServeHTTP(c.Writer, c.Request) } +} - http.HandleFunc("/minio/get_chunks", minio.GetSuccessChunks) - http.HandleFunc("/minio/new_multipart", minio.NewMultipart) - http.HandleFunc("/minio/get_multipart_url", minio.GetMultipartUploadURL) - http.HandleFunc("/minio/complete_multipart", minio.CompleteMultipart) - http.HandleFunc("/minio/update_chunk", minio.UpdateMultipart) - - klog.Infof("listening server on port: %d", *port) - log.Fatal(http.ListenAndServe(fmt.Sprintf("%s:%d", *host, *port), nil)) +func chatHandler() gin.HandlerFunc { + return func(c *gin.Context) { + req := chat.ChatReqBody{} + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + resp, err := chat.AppRun(c, req) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, resp) + } } diff --git a/graphql-server/go-server/pkg/chat/chat.go b/graphql-server/go-server/pkg/chat/chat.go new file mode 100644 index 000000000..628a5d5dc --- /dev/null +++ b/graphql-server/go-server/pkg/chat/chat.go @@ -0,0 +1,65 @@ +package chat + +import ( + "context" + "errors" + "time" + + "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/auth" + "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/client" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/uuid" +) + +var Coversions = map[string]Conversion{} + +func AppRun(ctx context.Context, req ChatReqBody) (*ChatRespBody, error) { + token := auth.ForOIDCToken(ctx) + c, err := client.GetClient(token) + if err != nil { + return nil, err + } + obj, err := c.Resource(schema.GroupVersionResource{Group: v1alpha1.GroupVersion.Group, Version: v1alpha1.GroupVersion.Version, Resource: "applications"}). + Namespace(req.AppNamespace).Get(ctx, req.APPName, metav1.GetOptions{}) + if err != nil { + return nil, err + } + app := &v1alpha1.Application{} + err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), app) + if err != nil { + return nil, err + } + if !app.Status.IsReady() { + return nil, errors.New("application is not ready") + } + var conversion Conversion + if req.ConversionID != "" { + var ok bool + conversion, ok = Coversions[req.ConversionID] + if !ok { + return nil, errors.New("conversion is not found") + } + if conversion.AppName != req.APPName || conversion.AppNamespce != req.AppNamespace { + return nil, errors.New("conversion id not match with app info") + } + } else { + conversion = Conversion{ + ID: string(uuid.NewUUID()), + AppName: req.APPName, + AppNamespce: req.AppNamespace, + StartedAt: time.Now(), + UpdatedAt: time.Now(), + Messages: make([]Message, 0), + } + conversion.Messages = append(conversion.Messages, Message{ + ID: string(uuid.NewUUID()), + Query: req.Query, + Answer: "", + }) + } + for i, node := range +} +// todo Reuse the flow without having to rebuild req same, not finish, Flow doesn't start with/contain nodes that depend on incomingInput.question diff --git a/graphql-server/go-server/pkg/chat/chat_type.go b/graphql-server/go-server/pkg/chat/chat_type.go new file mode 100644 index 000000000..8857f8794 --- /dev/null +++ b/graphql-server/go-server/pkg/chat/chat_type.go @@ -0,0 +1,41 @@ +package chat + +import "time" + +type ResponseMode string + +const ( + Blocking ResponseMode = "blocking" + Streaming ResponseMode = "streaming" + // todo isFlowValidForStream only some node(llm chain) support streaming +) + +type ChatReqBody struct { + Query string `json:"query" binding:"required"` + ResponseMode ResponseMode `json:"response_mode" binding:"required"` + ConversionID string `json:"conversion_id" binding:"required"` + APPName string `json:"app_name" binding:"required"` + AppNamespace string `json:"app_namespace" binding:"required"` +} + +type ChatRespBody struct { + ConversionID string `json:"conversion_id"` + MessageID string `json:"message_id"` + Message string `json:"message"` + CreatedAt time.Time `json:"created_at"` +} + +type Conversion struct { + ID string `json:"id"` + AppName string `json:"app_name"` + AppNamespce string `json:"app_namespace"` + StartedAt time.Time `json:"started_at"` + UpdatedAt time.Time `json:"updated_at"` + Messages []Message `json:"messages"` +} + +type Message struct { + ID string `json:"id"` + Query string `json:"query"` + Answer string `json:"answer"` +} diff --git a/main.go b/main.go index 68da8fff3..bbe1384f4 100644 --- a/main.go +++ b/main.go @@ -33,7 +33,11 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + apichain "github.com/kubeagi/arcadia/api/v1alpha1/node/chain" + apiprompttemplate "github.com/kubeagi/arcadia/api/v1alpha1/node/prompttemplate" "github.com/kubeagi/arcadia/controllers" + chaincontrollers "github.com/kubeagi/arcadia/controllers/node/chain" + prompttemplatecontrollers "github.com/kubeagi/arcadia/controllers/node/prompttemplate" "github.com/kubeagi/arcadia/pkg/utils" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) @@ -50,6 +54,8 @@ func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(arcadiav1alpha1.AddToScheme(scheme)) + utilruntime.Must(apichain.AddToScheme(scheme)) + utilruntime.Must(apiprompttemplate.AddToScheme(scheme)) //+kubebuilder:scaffold:scheme } @@ -204,6 +210,27 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "VectorStore") os.Exit(1) } + if err = (&controllers.ApplicationReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Application") + os.Exit(1) + } + if err = (&chaincontrollers.LLMChainReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "LLMChain") + os.Exit(1) + } + if err = (&prompttemplatecontrollers.PromptTemplateReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "PromptTemplate") + os.Exit(1) + } //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/pkg/application/app_run.go b/pkg/application/app_run.go new file mode 100644 index 000000000..63096e4d2 --- /dev/null +++ b/pkg/application/app_run.go @@ -0,0 +1,175 @@ +package application + +import ( + "container/list" + "context" + "errors" + "reflect" + "strings" + + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/pkg/application/chain" + "github.com/tmc/langchaingo/schema" +) + +type Input struct { + Question string + History []schema.ChatMessage + // overrideConfig +} +type Output struct { + Answer string +} + +type Application struct { + Spec arcadiav1alpha1.ApplicationSpec + Inited bool + Nodes map[string]*Node + StartingNodes []*Node + EndingNode *Node +} + +var cache = map[string]*Application{} + +func cacheKey(app *arcadiav1alpha1.Application) string { + return app.Namespace + "/" + app.Name +} + +func NewAppOrGetFromCache(ctx context.Context, app *arcadiav1alpha1.Application) (*Application, error) { + if app == nil || app.Name == "" || app.Namespace == "" { + return nil, errors.New("app has no name or namespace") + } + a, ok := cache[cacheKey(app)] + if !ok { + a = &Application{ + Spec: app.Spec, + } + cache[cacheKey(app)] = a + return a, nil + } + if reflect.DeepEqual(a.Spec, app.Spec) { + return a, nil + } + a.Spec = app.Spec + a.Inited = false + return a, a.Init(ctx) +} + +// todo 防止无限循环,需要找一下是不是成环 +func (a *Application) Init(ctx context.Context) (err error) { + if a.Inited { + return + } + a.Nodes = make(map[string]*Node) + + var inputNodeName, outputNodeName string + for _, node := range a.Spec.Nodes { + if node.Ref != nil && node.Ref.Kind == arcadiav1alpha1.OutputNode { + outputNodeName = node.Name + } + if node.Ref != nil && node.Ref.Kind == arcadiav1alpha1.InputNode { + inputNodeName = node.Name + } + } + + for _, node := range a.Spec.Nodes { + if node.Name == inputNodeName { + for _, n := range node.NextNodeName { + no, ok := a.Nodes[n] + if !ok { + a.Nodes[n] = &Node{Name: n, ConnectToInput: true} + } else { + no.ConnectToInput = true + } + a.StartingNodes = append(a.StartingNodes, no) + } + continue + } else if node.Name == outputNodeName { + continue + } + + n, ok := a.Nodes[node.Name] + if !ok { + n = &Node{Name: node.Name, Ref: node.Ref} + a.Nodes[node.Name] = n + } + n.Ref = node.Ref + for _, next := range node.NextNodeName { + if next == outputNodeName { + n.ConnectToOutput = true + } + n, ok := a.Nodes[next] + if !ok { + n = &Node{Name: next} + a.Nodes[next] = n + } + n.Next = append(n.Next, n) + } + } + + for _, v := range a.Nodes { + for _, n := range v.Next { + n.Before = append(n.Before, v) + } + } + + for _, v := range a.StartingNodes { + v.Core.New(ctx) + } + return nil +} + +func (a *Application) Run(ctx context.Context, input Input) (output Output, err error) { + waitRunningNodes := list.New() + for _, v := range a.StartingNodes { + waitRunningNodes.PushBack(v) + } + for e := waitRunningNodes.Front(); e != nil; e = e.Next() { + node := e.Value.(*Node) + out, err := node.Core.Execute(ctx, input) + if err != nil { + return Output{}, err + } + for _, n := range node.Next { + waitRunningNodes.PushBack(n) + } + } + return Output{Answer: out}, nil +} + +func InitNode(name string, ref *arcadiav1alpha1.TypedObjectReference) (*Node, error) { + if ref == nil { + return nil, errors.New("ref is nil") + } + group := ref.APIGroup + if group == nil { + return nil, errors.New("group is nil") + } + before, _, _ := strings.Cut(*group, "/") + groups := strings.ToLower(strings.TrimSuffix(before, ".arcadia.kubeagi.k8s.com.cn")) + kind := strings.ToLower(ref.Kind) + switch groups { + case "chain": + switch kind { + case "llmchain": + chain.NewLLMChain() + default: + return nil, errors.New("kind is not found") + } + case "llm": + switch kind { + case "llmchain": + default: + return nil, errors.New("kind is not found") + } + case "prompt": + switch kind { + case "llmchain": + default: + return nil, errors.New("kind is not found") + } + default: + return nil, errors.New("group is not found") + } + return nil, nil +} diff --git a/pkg/application/chain/llmchain.go b/pkg/application/chain/llmchain.go new file mode 100644 index 000000000..6dfe049cd --- /dev/null +++ b/pkg/application/chain/llmchain.go @@ -0,0 +1,34 @@ +package chain + +import ( + "context" + + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/pkg/application" + "github.com/tmc/langchaingo/chains" + "github.com/tmc/langchaingo/llms" + "github.com/tmc/langchaingo/prompts" +) + +type LLMChain struct { + *chains.LLMChain + *application.CoreNode +} + +func NewLLMChain(llm llms.LanguageModel, prompt prompts.FormatPrompter, nodeName string, ref *arcadiav1alpha1.TypedObjectReference) *LLMChain { + chain := chains.NewLLMChain(llm, prompt) + coreNode := application.NewCoreNode(nodeName, ref) + return &LLMChain{ + chain, + coreNode, + } +} + +func (L LLMChain) Init(ctx context.Context) error { + //TODO implement me + panic("implement me") +} + +func (L LLMChain) Execute(ctx context.Context, arg map[string]any) (string, error) { + return chains.Predict(ctx, L, arg) +} diff --git a/pkg/application/llm/zhipu.go b/pkg/application/llm/zhipu.go new file mode 100644 index 000000000..1c920459b --- /dev/null +++ b/pkg/application/llm/zhipu.go @@ -0,0 +1,21 @@ +package llm + +import ( + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/pkg/application" + "github.com/kubeagi/arcadia/pkg/llms/zhipuai" +) + +type ZhipuLLM struct { + *zhipuai.ZhiPuAI + *application.CoreNode +} + +func NewZhipuLLM(apikey string, nodeName string, ref *arcadiav1alpha1.TypedObjectReference) *ZhipuLLM { + zhipu := zhipuai.NewZhiPuAI(apikey) + coreNode := application.NewCoreNode(nodeName, ref) + return &ZhipuLLM{ + zhipu, + coreNode, + } +} diff --git a/pkg/application/node.go b/pkg/application/node.go new file mode 100644 index 000000000..64c35dea4 --- /dev/null +++ b/pkg/application/node.go @@ -0,0 +1,62 @@ +package application + +import ( + "context" + "strings" + + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" +) + +type Node interface { + Type() string + Kind() string + Init(ctx context.Context) error + Run(ctx context.Context, args map[string]any) (string, error) +} + +func NewCoreNode(nodeName string, ref *arcadiav1alpha1.TypedObjectReference) *CoreNode { + return &CoreNode{ + Name: nodeName, + Ref: ref, + Before: make([]*CoreNode, 0), + Next: make([]*CoreNode, 0), + ConnectToInput: false, + ConnectToOutput: false, + } +} + +type CoreNode struct { + Name string + Ref *arcadiav1alpha1.TypedObjectReference + Before []*CoreNode + Next []*CoreNode + ConnectToInput bool + ConnectToOutput bool +} + +func (c *CoreNode) Type() string { + if c.Ref == nil { + return "" + } + group := c.Ref.APIGroup + if group == nil { + return "" + } + before, _, _ := strings.Cut(*group, "/") + return strings.TrimSuffix(before, ".arcadia.kubeagi.k8s.com.cn") +} + +func (c *CoreNode) Kind() string { + if c.Ref == nil { + return "" + } + return c.Ref.Kind +} + +func (c *CoreNode) Init(ctx context.Context) error { + return nil +} + +func (c *CoreNode) Run(ctx context.Context, args map[string]any) (string, error) { + return "", nil +} diff --git a/pkg/application/prompttemplate/prompttemplate.go b/pkg/application/prompttemplate/prompttemplate.go new file mode 100644 index 000000000..57c8932de --- /dev/null +++ b/pkg/application/prompttemplate/prompttemplate.go @@ -0,0 +1,25 @@ +package prompttemplate + +import ( + "context" + + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/pkg/application" + "github.com/tmc/langchaingo/prompts" +) + +type PromptTemplate struct { + prompts.PromptTemplate + *application.CoreNode +} + +func NewPromptTemplate(nodeName string, ref *arcadiav1alpha1.TypedObjectReference, template string, inputVars []string) *PromptTemplate { + return &PromptTemplate{ + prompts.NewPromptTemplate(template, inputVars), + application.NewCoreNode(nodeName, ref), + } +} + +func (p PromptTemplate) Execute(ctx context.Context, arg map[string]any) (string, error) { + return p.Format(arg) +}