intentkit 0.7.4rc1__py3-none-any.whl → 0.7.5.dev1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of intentkit might be problematic. Click here for more details.
- intentkit/__init__.py +1 -1
- intentkit/clients/cdp.py +1 -1
- intentkit/core/agent.py +465 -3
- intentkit/core/engine.py +7 -26
- intentkit/core/prompt.py +1 -1
- intentkit/models/agent.py +208 -410
- intentkit/models/agent_schema.json +0 -39
- intentkit/models/db.py +1 -1
- intentkit/models/user.py +12 -5
- intentkit/utils/chain.py +3 -3
- {intentkit-0.7.4rc1.dist-info → intentkit-0.7.5.dev1.dist-info}/METADATA +1 -1
- {intentkit-0.7.4rc1.dist-info → intentkit-0.7.5.dev1.dist-info}/RECORD +14 -15
- intentkit/core/skill.py +0 -200
- {intentkit-0.7.4rc1.dist-info → intentkit-0.7.5.dev1.dist-info}/WHEEL +0 -0
- {intentkit-0.7.4rc1.dist-info → intentkit-0.7.5.dev1.dist-info}/licenses/LICENSE +0 -0
intentkit/models/agent.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import hashlib
|
|
1
2
|
import json
|
|
2
3
|
import logging
|
|
3
4
|
import re
|
|
@@ -14,10 +15,11 @@ from epyxid import XID
|
|
|
14
15
|
from fastapi import HTTPException
|
|
15
16
|
from intentkit.models.agent_data import AgentData
|
|
16
17
|
from intentkit.models.base import Base
|
|
18
|
+
from intentkit.models.credit import CreditAccount
|
|
17
19
|
from intentkit.models.db import get_session
|
|
18
20
|
from intentkit.models.llm import LLMModelInfo, LLMModelInfoTable, LLMProvider
|
|
19
21
|
from intentkit.models.skill import SkillTable
|
|
20
|
-
from pydantic import BaseModel, ConfigDict, field_validator
|
|
22
|
+
from pydantic import BaseModel, ConfigDict, field_validator
|
|
21
23
|
from pydantic import Field as PydanticField
|
|
22
24
|
from pydantic.json_schema import SkipJsonSchema
|
|
23
25
|
from sqlalchemy import (
|
|
@@ -128,33 +130,6 @@ class AgentAutonomous(BaseModel):
|
|
|
128
130
|
)
|
|
129
131
|
return v
|
|
130
132
|
|
|
131
|
-
@field_validator("name")
|
|
132
|
-
@classmethod
|
|
133
|
-
def validate_name(cls, v: Optional[str]) -> Optional[str]:
|
|
134
|
-
if v is not None and len(v.encode()) > 50:
|
|
135
|
-
raise ValueError("name must be at most 50 bytes")
|
|
136
|
-
return v
|
|
137
|
-
|
|
138
|
-
@field_validator("description")
|
|
139
|
-
@classmethod
|
|
140
|
-
def validate_description(cls, v: Optional[str]) -> Optional[str]:
|
|
141
|
-
if v is not None and len(v.encode()) > 200:
|
|
142
|
-
raise ValueError("description must be at most 200 bytes")
|
|
143
|
-
return v
|
|
144
|
-
|
|
145
|
-
@field_validator("prompt")
|
|
146
|
-
@classmethod
|
|
147
|
-
def validate_prompt(cls, v: Optional[str]) -> Optional[str]:
|
|
148
|
-
if v is not None and len(v.encode()) > 20000:
|
|
149
|
-
raise ValueError("prompt must be at most 20000 bytes")
|
|
150
|
-
return v
|
|
151
|
-
|
|
152
|
-
@model_validator(mode="after")
|
|
153
|
-
def validate_schedule(self) -> "AgentAutonomous":
|
|
154
|
-
# This validator is kept for backward compatibility
|
|
155
|
-
# The actual validation now happens in AgentUpdate.validate_autonomous_schedule
|
|
156
|
-
return self
|
|
157
|
-
|
|
158
133
|
|
|
159
134
|
class AgentExample(BaseModel):
|
|
160
135
|
"""Agent example configuration."""
|
|
@@ -241,11 +216,6 @@ class AgentTable(Base):
|
|
|
241
216
|
nullable=True,
|
|
242
217
|
comment="Pool of the agent token",
|
|
243
218
|
)
|
|
244
|
-
mode = Column(
|
|
245
|
-
String,
|
|
246
|
-
nullable=True,
|
|
247
|
-
comment="Mode of the agent, public or private",
|
|
248
|
-
)
|
|
249
219
|
fee_percentage = Column(
|
|
250
220
|
Numeric(22, 4),
|
|
251
221
|
nullable=True,
|
|
@@ -362,13 +332,6 @@ class AgentTable(Base):
|
|
|
362
332
|
nullable=True,
|
|
363
333
|
comment="Dict of skills and their corresponding configurations",
|
|
364
334
|
)
|
|
365
|
-
|
|
366
|
-
cdp_network_id = Column(
|
|
367
|
-
String,
|
|
368
|
-
nullable=True,
|
|
369
|
-
default="base-mainnet",
|
|
370
|
-
comment="Network identifier for CDP integration",
|
|
371
|
-
)
|
|
372
335
|
# if telegram_entrypoint_enabled, the telegram_entrypoint_enabled will be enabled, telegram_config will be checked
|
|
373
336
|
telegram_entrypoint_enabled = Column(
|
|
374
337
|
Boolean,
|
|
@@ -391,6 +354,31 @@ class AgentTable(Base):
|
|
|
391
354
|
nullable=True,
|
|
392
355
|
comment="Extra prompt for xmtp entrypoint",
|
|
393
356
|
)
|
|
357
|
+
version = Column(
|
|
358
|
+
String,
|
|
359
|
+
nullable=True,
|
|
360
|
+
comment="Version hash of the agent",
|
|
361
|
+
)
|
|
362
|
+
statistics = Column(
|
|
363
|
+
JSON().with_variant(JSONB(), "postgresql"),
|
|
364
|
+
nullable=True,
|
|
365
|
+
comment="Statistics of the agent, update every 1 hour for query",
|
|
366
|
+
)
|
|
367
|
+
assets = Column(
|
|
368
|
+
JSON().with_variant(JSONB(), "postgresql"),
|
|
369
|
+
nullable=True,
|
|
370
|
+
comment="Assets of the agent, update every 1 hour for query",
|
|
371
|
+
)
|
|
372
|
+
account_snapshot = Column(
|
|
373
|
+
JSON().with_variant(JSONB(), "postgresql"),
|
|
374
|
+
nullable=True,
|
|
375
|
+
comment="Account snapshot of the agent, update every 1 hour for query",
|
|
376
|
+
)
|
|
377
|
+
extra = Column(
|
|
378
|
+
JSON().with_variant(JSONB(), "postgresql"),
|
|
379
|
+
nullable=True,
|
|
380
|
+
comment="Other helper data fields for query, come from agent and agent data",
|
|
381
|
+
)
|
|
394
382
|
# auto timestamp
|
|
395
383
|
created_at = Column(
|
|
396
384
|
DateTime(timezone=True),
|
|
@@ -407,16 +395,8 @@ class AgentTable(Base):
|
|
|
407
395
|
)
|
|
408
396
|
|
|
409
397
|
|
|
410
|
-
class
|
|
411
|
-
"""Agent
|
|
412
|
-
|
|
413
|
-
model_config = ConfigDict(
|
|
414
|
-
title="Agent",
|
|
415
|
-
from_attributes=True,
|
|
416
|
-
json_schema_extra={
|
|
417
|
-
"required": ["name", "purpose", "personality", "principles"],
|
|
418
|
-
},
|
|
419
|
-
)
|
|
398
|
+
class AgentCore(BaseModel):
|
|
399
|
+
"""Agent core model."""
|
|
420
400
|
|
|
421
401
|
name: Annotated[
|
|
422
402
|
Optional[str],
|
|
@@ -431,19 +411,6 @@ class AgentUpdate(BaseModel):
|
|
|
431
411
|
},
|
|
432
412
|
),
|
|
433
413
|
]
|
|
434
|
-
slug: Annotated[
|
|
435
|
-
Optional[str],
|
|
436
|
-
PydanticField(
|
|
437
|
-
default=None,
|
|
438
|
-
description="Slug of the agent, used for URL generation",
|
|
439
|
-
max_length=30,
|
|
440
|
-
min_length=2,
|
|
441
|
-
json_schema_extra={
|
|
442
|
-
"x-group": "internal",
|
|
443
|
-
"readOnly": True,
|
|
444
|
-
},
|
|
445
|
-
),
|
|
446
|
-
]
|
|
447
414
|
description: Annotated[
|
|
448
415
|
Optional[str],
|
|
449
416
|
PydanticField(
|
|
@@ -515,16 +482,6 @@ class AgentUpdate(BaseModel):
|
|
|
515
482
|
},
|
|
516
483
|
),
|
|
517
484
|
]
|
|
518
|
-
mode: Annotated[
|
|
519
|
-
Optional[Literal["public", "private"]],
|
|
520
|
-
PydanticField(
|
|
521
|
-
default=None,
|
|
522
|
-
description="Mode of the agent, public or private",
|
|
523
|
-
json_schema_extra={
|
|
524
|
-
"x-group": "basic",
|
|
525
|
-
},
|
|
526
|
-
),
|
|
527
|
-
]
|
|
528
485
|
fee_percentage: Annotated[
|
|
529
486
|
Optional[Decimal],
|
|
530
487
|
PydanticField(
|
|
@@ -584,38 +541,6 @@ class AgentUpdate(BaseModel):
|
|
|
584
541
|
},
|
|
585
542
|
),
|
|
586
543
|
]
|
|
587
|
-
owner: Annotated[
|
|
588
|
-
Optional[str],
|
|
589
|
-
PydanticField(
|
|
590
|
-
default=None,
|
|
591
|
-
description="Owner identifier of the agent, used for access control",
|
|
592
|
-
max_length=50,
|
|
593
|
-
json_schema_extra={
|
|
594
|
-
"x-group": "internal",
|
|
595
|
-
},
|
|
596
|
-
),
|
|
597
|
-
]
|
|
598
|
-
upstream_id: Annotated[
|
|
599
|
-
Optional[str],
|
|
600
|
-
PydanticField(
|
|
601
|
-
default=None,
|
|
602
|
-
description="External reference ID for idempotent operations",
|
|
603
|
-
max_length=100,
|
|
604
|
-
json_schema_extra={
|
|
605
|
-
"x-group": "internal",
|
|
606
|
-
},
|
|
607
|
-
),
|
|
608
|
-
]
|
|
609
|
-
upstream_extra: Annotated[
|
|
610
|
-
Optional[Dict[str, Any]],
|
|
611
|
-
PydanticField(
|
|
612
|
-
default=None,
|
|
613
|
-
description="Additional data store for upstream use",
|
|
614
|
-
json_schema_extra={
|
|
615
|
-
"x-group": "internal",
|
|
616
|
-
},
|
|
617
|
-
),
|
|
618
|
-
]
|
|
619
544
|
# AI part
|
|
620
545
|
model: Annotated[
|
|
621
546
|
str,
|
|
@@ -693,6 +618,89 @@ class AgentUpdate(BaseModel):
|
|
|
693
618
|
},
|
|
694
619
|
),
|
|
695
620
|
]
|
|
621
|
+
wallet_provider: Annotated[
|
|
622
|
+
Optional[Literal["cdp", "readonly"]],
|
|
623
|
+
PydanticField(
|
|
624
|
+
default="cdp",
|
|
625
|
+
description="Provider of the agent's wallet",
|
|
626
|
+
json_schema_extra={
|
|
627
|
+
"x-group": "onchain",
|
|
628
|
+
},
|
|
629
|
+
),
|
|
630
|
+
]
|
|
631
|
+
readonly_wallet_address: Annotated[
|
|
632
|
+
Optional[str],
|
|
633
|
+
PydanticField(
|
|
634
|
+
default=None,
|
|
635
|
+
description="Address of the agent's wallet, only used when wallet_provider is readonly. Agent will not be able to sign transactions.",
|
|
636
|
+
),
|
|
637
|
+
]
|
|
638
|
+
network_id: Annotated[
|
|
639
|
+
Optional[
|
|
640
|
+
Literal[
|
|
641
|
+
"ethereum-mainnet",
|
|
642
|
+
"ethereum-sepolia",
|
|
643
|
+
"polygon-mainnet",
|
|
644
|
+
"polygon-mumbai",
|
|
645
|
+
"base-mainnet",
|
|
646
|
+
"base-sepolia",
|
|
647
|
+
"arbitrum-mainnet",
|
|
648
|
+
"arbitrum-sepolia",
|
|
649
|
+
"optimism-mainnet",
|
|
650
|
+
"optimism-sepolia",
|
|
651
|
+
"solana",
|
|
652
|
+
]
|
|
653
|
+
],
|
|
654
|
+
PydanticField(
|
|
655
|
+
default="base-mainnet",
|
|
656
|
+
description="Network identifier",
|
|
657
|
+
json_schema_extra={
|
|
658
|
+
"x-group": "onchain",
|
|
659
|
+
},
|
|
660
|
+
),
|
|
661
|
+
]
|
|
662
|
+
skills: Annotated[
|
|
663
|
+
Optional[Dict[str, Any]],
|
|
664
|
+
PydanticField(
|
|
665
|
+
default=None,
|
|
666
|
+
description="Dict of skills and their corresponding configurations",
|
|
667
|
+
json_schema_extra={
|
|
668
|
+
"x-group": "skills",
|
|
669
|
+
"x-inline": True,
|
|
670
|
+
},
|
|
671
|
+
),
|
|
672
|
+
]
|
|
673
|
+
|
|
674
|
+
def hash(self) -> str:
|
|
675
|
+
"""
|
|
676
|
+
Generate a fixed-length hash based on the agent's content.
|
|
677
|
+
|
|
678
|
+
The hash remains unchanged if the content is the same and changes if the content changes.
|
|
679
|
+
This method serializes only AgentCore fields to JSON and generates a SHA-256 hash.
|
|
680
|
+
When called from subclasses, it will only use AgentCore fields, not subclass fields.
|
|
681
|
+
|
|
682
|
+
Returns:
|
|
683
|
+
str: A 64-character hexadecimal hash string
|
|
684
|
+
"""
|
|
685
|
+
# Create a dictionary with only AgentCore fields for hashing
|
|
686
|
+
hash_data = {}
|
|
687
|
+
|
|
688
|
+
# Get only AgentCore field values, excluding None values for consistency
|
|
689
|
+
for field_name in AgentCore.model_fields:
|
|
690
|
+
value = getattr(self, field_name)
|
|
691
|
+
if value is not None:
|
|
692
|
+
hash_data[field_name] = value
|
|
693
|
+
|
|
694
|
+
# Convert to JSON string with sorted keys for consistent ordering
|
|
695
|
+
json_str = json.dumps(hash_data, sort_keys=True, default=str, ensure_ascii=True)
|
|
696
|
+
|
|
697
|
+
# Generate SHA-256 hash
|
|
698
|
+
return hashlib.sha256(json_str.encode("utf-8")).hexdigest()
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
class AgentUserInput(AgentCore):
|
|
702
|
+
"""Agent update model."""
|
|
703
|
+
|
|
696
704
|
short_term_memory_strategy: Annotated[
|
|
697
705
|
Optional[Literal["trim", "summarize"]],
|
|
698
706
|
PydanticField(
|
|
@@ -751,82 +759,6 @@ class AgentUpdate(BaseModel):
|
|
|
751
759
|
},
|
|
752
760
|
),
|
|
753
761
|
]
|
|
754
|
-
# skills
|
|
755
|
-
skills: Annotated[
|
|
756
|
-
Optional[Dict[str, Any]],
|
|
757
|
-
PydanticField(
|
|
758
|
-
default=None,
|
|
759
|
-
description="Dict of skills and their corresponding configurations",
|
|
760
|
-
json_schema_extra={
|
|
761
|
-
"x-group": "skills",
|
|
762
|
-
"x-inline": True,
|
|
763
|
-
},
|
|
764
|
-
),
|
|
765
|
-
]
|
|
766
|
-
wallet_provider: Annotated[
|
|
767
|
-
Optional[Literal["cdp", "readonly"]],
|
|
768
|
-
PydanticField(
|
|
769
|
-
default="cdp",
|
|
770
|
-
description="Provider of the agent's wallet",
|
|
771
|
-
json_schema_extra={
|
|
772
|
-
"x-group": "onchain",
|
|
773
|
-
},
|
|
774
|
-
),
|
|
775
|
-
]
|
|
776
|
-
readonly_wallet_address: Annotated[
|
|
777
|
-
Optional[str],
|
|
778
|
-
PydanticField(
|
|
779
|
-
default=None,
|
|
780
|
-
description="Address of the agent's wallet, only used when wallet_provider is readonly. Agent will not be able to sign transactions.",
|
|
781
|
-
),
|
|
782
|
-
]
|
|
783
|
-
network_id: Annotated[
|
|
784
|
-
Optional[
|
|
785
|
-
Literal[
|
|
786
|
-
"ethereum-mainnet",
|
|
787
|
-
"ethereum-sepolia",
|
|
788
|
-
"polygon-mainnet",
|
|
789
|
-
"polygon-mumbai",
|
|
790
|
-
"base-mainnet",
|
|
791
|
-
"base-sepolia",
|
|
792
|
-
"arbitrum-mainnet",
|
|
793
|
-
"arbitrum-sepolia",
|
|
794
|
-
"optimism-mainnet",
|
|
795
|
-
"optimism-sepolia",
|
|
796
|
-
"solana",
|
|
797
|
-
]
|
|
798
|
-
],
|
|
799
|
-
PydanticField(
|
|
800
|
-
default="base-mainnet",
|
|
801
|
-
description="Network identifier",
|
|
802
|
-
json_schema_extra={
|
|
803
|
-
"x-group": "onchain",
|
|
804
|
-
},
|
|
805
|
-
),
|
|
806
|
-
]
|
|
807
|
-
cdp_network_id: Annotated[
|
|
808
|
-
Optional[
|
|
809
|
-
Literal[
|
|
810
|
-
"ethereum-mainnet",
|
|
811
|
-
"ethereum-sepolia",
|
|
812
|
-
"polygon-mainnet",
|
|
813
|
-
"polygon-mumbai",
|
|
814
|
-
"base-mainnet",
|
|
815
|
-
"base-sepolia",
|
|
816
|
-
"arbitrum-mainnet",
|
|
817
|
-
"arbitrum-sepolia",
|
|
818
|
-
"optimism-mainnet",
|
|
819
|
-
"optimism-sepolia",
|
|
820
|
-
]
|
|
821
|
-
],
|
|
822
|
-
PydanticField(
|
|
823
|
-
default="base-mainnet",
|
|
824
|
-
description="Network identifier for CDP integration",
|
|
825
|
-
json_schema_extra={
|
|
826
|
-
"x-group": "deprecated",
|
|
827
|
-
},
|
|
828
|
-
),
|
|
829
|
-
]
|
|
830
762
|
# if telegram_entrypoint_enabled, the telegram_entrypoint_enabled will be enabled, telegram_config will be checked
|
|
831
763
|
telegram_entrypoint_enabled: Annotated[
|
|
832
764
|
Optional[bool],
|
|
@@ -871,6 +803,37 @@ class AgentUpdate(BaseModel):
|
|
|
871
803
|
),
|
|
872
804
|
]
|
|
873
805
|
|
|
806
|
+
|
|
807
|
+
class AgentUpdate(AgentUserInput):
|
|
808
|
+
"""Agent update model."""
|
|
809
|
+
|
|
810
|
+
model_config = ConfigDict(
|
|
811
|
+
title="Agent",
|
|
812
|
+
from_attributes=True,
|
|
813
|
+
json_schema_extra={
|
|
814
|
+
"required": ["name"],
|
|
815
|
+
},
|
|
816
|
+
)
|
|
817
|
+
|
|
818
|
+
upstream_id: Annotated[
|
|
819
|
+
Optional[str],
|
|
820
|
+
PydanticField(
|
|
821
|
+
default=None,
|
|
822
|
+
description="External reference ID for idempotent operations",
|
|
823
|
+
max_length=100,
|
|
824
|
+
),
|
|
825
|
+
]
|
|
826
|
+
upstream_extra: Annotated[
|
|
827
|
+
Optional[Dict[str, Any]],
|
|
828
|
+
PydanticField(
|
|
829
|
+
default=None,
|
|
830
|
+
description="Additional data store for upstream use",
|
|
831
|
+
json_schema_extra={
|
|
832
|
+
"x-group": "internal",
|
|
833
|
+
},
|
|
834
|
+
),
|
|
835
|
+
]
|
|
836
|
+
|
|
874
837
|
@field_validator("purpose", "personality", "principles", "prompt", "prompt_append")
|
|
875
838
|
@classmethod
|
|
876
839
|
def validate_no_level1_level2_headings(cls, v: Optional[str]) -> Optional[str]:
|
|
@@ -960,6 +923,7 @@ class AgentUpdate(BaseModel):
|
|
|
960
923
|
detail="The shortest execution interval is 5 minutes",
|
|
961
924
|
)
|
|
962
925
|
|
|
926
|
+
# deprecated, use override instead
|
|
963
927
|
async def update(self, id: str) -> "Agent":
|
|
964
928
|
# Validate autonomous schedule settings if present
|
|
965
929
|
if "autonomous" in self.model_dump(exclude_unset=True):
|
|
@@ -969,12 +933,6 @@ class AgentUpdate(BaseModel):
|
|
|
969
933
|
db_agent = await db.get(AgentTable, id)
|
|
970
934
|
if not db_agent:
|
|
971
935
|
raise HTTPException(status_code=404, detail="Agent not found")
|
|
972
|
-
# check owner
|
|
973
|
-
if self.owner and db_agent.owner != self.owner:
|
|
974
|
-
raise HTTPException(
|
|
975
|
-
status_code=403,
|
|
976
|
-
detail="You do not have permission to update this agent",
|
|
977
|
-
)
|
|
978
936
|
# update
|
|
979
937
|
for key, value in self.model_dump(exclude_unset=True).items():
|
|
980
938
|
setattr(db_agent, key, value)
|
|
@@ -991,15 +949,11 @@ class AgentUpdate(BaseModel):
|
|
|
991
949
|
db_agent = await db.get(AgentTable, id)
|
|
992
950
|
if not db_agent:
|
|
993
951
|
raise HTTPException(status_code=404, detail="Agent not found")
|
|
994
|
-
# check owner
|
|
995
|
-
if db_agent.owner and db_agent.owner != self.owner:
|
|
996
|
-
raise HTTPException(
|
|
997
|
-
status_code=403,
|
|
998
|
-
detail="You do not have permission to update this agent",
|
|
999
|
-
)
|
|
1000
952
|
# update
|
|
1001
953
|
for key, value in self.model_dump().items():
|
|
1002
954
|
setattr(db_agent, key, value)
|
|
955
|
+
# version
|
|
956
|
+
db_agent.version = self.hash()
|
|
1003
957
|
await db.commit()
|
|
1004
958
|
await db.refresh(db_agent)
|
|
1005
959
|
return Agent.model_validate(db_agent)
|
|
@@ -1018,6 +972,14 @@ class AgentCreate(AgentUpdate):
|
|
|
1018
972
|
max_length=67,
|
|
1019
973
|
),
|
|
1020
974
|
]
|
|
975
|
+
owner: Annotated[
|
|
976
|
+
Optional[str],
|
|
977
|
+
PydanticField(
|
|
978
|
+
default=None,
|
|
979
|
+
description="Owner identifier of the agent, used for access control",
|
|
980
|
+
max_length=50,
|
|
981
|
+
),
|
|
982
|
+
]
|
|
1021
983
|
|
|
1022
984
|
async def check_upstream_id(self) -> None:
|
|
1023
985
|
if not self.upstream_id:
|
|
@@ -1050,45 +1012,56 @@ class AgentCreate(AgentUpdate):
|
|
|
1050
1012
|
|
|
1051
1013
|
async with get_session() as db:
|
|
1052
1014
|
db_agent = AgentTable(**self.model_dump())
|
|
1015
|
+
db_agent.version = self.hash()
|
|
1053
1016
|
db.add(db_agent)
|
|
1054
1017
|
await db.commit()
|
|
1055
1018
|
await db.refresh(db_agent)
|
|
1056
1019
|
return Agent.model_validate(db_agent)
|
|
1057
1020
|
|
|
1058
|
-
async def create_or_update(self) -> ("Agent", bool):
|
|
1059
|
-
# Validation is now handled by field validators
|
|
1060
|
-
await self.check_upstream_id()
|
|
1061
|
-
|
|
1062
|
-
# Validate autonomous schedule settings if present
|
|
1063
|
-
if self.autonomous:
|
|
1064
|
-
self.validate_autonomous_schedule()
|
|
1065
|
-
|
|
1066
|
-
is_new = False
|
|
1067
|
-
async with get_session() as db:
|
|
1068
|
-
db_agent = await db.get(AgentTable, self.id)
|
|
1069
|
-
if not db_agent:
|
|
1070
|
-
db_agent = AgentTable(**self.model_dump())
|
|
1071
|
-
db.add(db_agent)
|
|
1072
|
-
is_new = True
|
|
1073
|
-
else:
|
|
1074
|
-
# check owner
|
|
1075
|
-
if self.owner and db_agent.owner != self.owner:
|
|
1076
|
-
raise HTTPException(
|
|
1077
|
-
status_code=403,
|
|
1078
|
-
detail="You do not have permission to update this agent",
|
|
1079
|
-
)
|
|
1080
|
-
for key, value in self.model_dump(exclude_unset=True).items():
|
|
1081
|
-
setattr(db_agent, key, value)
|
|
1082
|
-
await db.commit()
|
|
1083
|
-
await db.refresh(db_agent)
|
|
1084
|
-
return Agent.model_validate(db_agent), is_new
|
|
1085
|
-
|
|
1086
1021
|
|
|
1087
1022
|
class Agent(AgentCreate):
|
|
1088
1023
|
"""Agent model."""
|
|
1089
1024
|
|
|
1090
1025
|
model_config = ConfigDict(from_attributes=True)
|
|
1091
1026
|
|
|
1027
|
+
slug: Annotated[
|
|
1028
|
+
Optional[str],
|
|
1029
|
+
PydanticField(
|
|
1030
|
+
default=None,
|
|
1031
|
+
description="Slug of the agent, used for URL generation",
|
|
1032
|
+
max_length=20,
|
|
1033
|
+
min_length=2,
|
|
1034
|
+
),
|
|
1035
|
+
]
|
|
1036
|
+
version: Annotated[
|
|
1037
|
+
Optional[str],
|
|
1038
|
+
PydanticField(
|
|
1039
|
+
default=None,
|
|
1040
|
+
description="Version hash of the agent",
|
|
1041
|
+
),
|
|
1042
|
+
]
|
|
1043
|
+
statistics: Annotated[
|
|
1044
|
+
Optional[Dict[str, Any]],
|
|
1045
|
+
PydanticField(
|
|
1046
|
+
description="Statistics of the agent, update every 1 hour for query"
|
|
1047
|
+
),
|
|
1048
|
+
]
|
|
1049
|
+
assets: Annotated[
|
|
1050
|
+
Optional[Dict[str, Any]],
|
|
1051
|
+
PydanticField(description="Assets of the agent, update every 1 hour for query"),
|
|
1052
|
+
]
|
|
1053
|
+
account_snapshot: Annotated[
|
|
1054
|
+
Optional[CreditAccount],
|
|
1055
|
+
PydanticField(
|
|
1056
|
+
description="Account snapshot of the agent, update every 1 hour for query"
|
|
1057
|
+
),
|
|
1058
|
+
]
|
|
1059
|
+
extra: Annotated[
|
|
1060
|
+
Optional[Dict[str, Any]],
|
|
1061
|
+
PydanticField(
|
|
1062
|
+
description="Other helper data fields for query, come from agent and agent data"
|
|
1063
|
+
),
|
|
1064
|
+
]
|
|
1092
1065
|
# auto timestamp
|
|
1093
1066
|
created_at: Annotated[
|
|
1094
1067
|
datetime,
|
|
@@ -1469,7 +1442,7 @@ class Agent(AgentCreate):
|
|
|
1469
1442
|
return schema
|
|
1470
1443
|
|
|
1471
1444
|
|
|
1472
|
-
class AgentResponse(
|
|
1445
|
+
class AgentResponse(Agent):
|
|
1473
1446
|
"""Response model for Agent API."""
|
|
1474
1447
|
|
|
1475
1448
|
model_config = ConfigDict(
|
|
@@ -1479,193 +1452,6 @@ class AgentResponse(BaseModel):
|
|
|
1479
1452
|
},
|
|
1480
1453
|
)
|
|
1481
1454
|
|
|
1482
|
-
id: Annotated[
|
|
1483
|
-
str,
|
|
1484
|
-
PydanticField(
|
|
1485
|
-
description="Unique identifier for the agent. Must be URL-safe, containing only lowercase letters, numbers, and hyphens",
|
|
1486
|
-
),
|
|
1487
|
-
]
|
|
1488
|
-
# auto timestamp
|
|
1489
|
-
created_at: Annotated[
|
|
1490
|
-
datetime,
|
|
1491
|
-
PydanticField(
|
|
1492
|
-
description="Timestamp when the agent was created, will ignore when importing"
|
|
1493
|
-
),
|
|
1494
|
-
]
|
|
1495
|
-
updated_at: Annotated[
|
|
1496
|
-
datetime,
|
|
1497
|
-
PydanticField(
|
|
1498
|
-
description="Timestamp when the agent was last updated, will ignore when importing"
|
|
1499
|
-
),
|
|
1500
|
-
]
|
|
1501
|
-
# Agent part
|
|
1502
|
-
name: Annotated[
|
|
1503
|
-
Optional[str],
|
|
1504
|
-
PydanticField(
|
|
1505
|
-
default=None,
|
|
1506
|
-
description="Display name of the agent",
|
|
1507
|
-
),
|
|
1508
|
-
]
|
|
1509
|
-
slug: Annotated[
|
|
1510
|
-
Optional[str],
|
|
1511
|
-
PydanticField(
|
|
1512
|
-
default=None,
|
|
1513
|
-
description="Slug of the agent, used for URL generation",
|
|
1514
|
-
),
|
|
1515
|
-
]
|
|
1516
|
-
description: Annotated[
|
|
1517
|
-
Optional[str],
|
|
1518
|
-
PydanticField(
|
|
1519
|
-
default=None,
|
|
1520
|
-
description="Description of the agent, for public view, not contained in prompt",
|
|
1521
|
-
),
|
|
1522
|
-
]
|
|
1523
|
-
external_website: Annotated[
|
|
1524
|
-
Optional[str],
|
|
1525
|
-
PydanticField(
|
|
1526
|
-
default=None,
|
|
1527
|
-
description="Link of external website of the agent, if you have one",
|
|
1528
|
-
),
|
|
1529
|
-
]
|
|
1530
|
-
picture: Annotated[
|
|
1531
|
-
Optional[str],
|
|
1532
|
-
PydanticField(
|
|
1533
|
-
default=None,
|
|
1534
|
-
description="Picture of the agent",
|
|
1535
|
-
),
|
|
1536
|
-
]
|
|
1537
|
-
ticker: Annotated[
|
|
1538
|
-
Optional[str],
|
|
1539
|
-
PydanticField(
|
|
1540
|
-
default=None,
|
|
1541
|
-
description="Ticker symbol of the agent",
|
|
1542
|
-
),
|
|
1543
|
-
]
|
|
1544
|
-
token_address: Annotated[
|
|
1545
|
-
Optional[str],
|
|
1546
|
-
PydanticField(
|
|
1547
|
-
default=None,
|
|
1548
|
-
description="Token address of the agent",
|
|
1549
|
-
),
|
|
1550
|
-
]
|
|
1551
|
-
token_pool: Annotated[
|
|
1552
|
-
Optional[str],
|
|
1553
|
-
PydanticField(
|
|
1554
|
-
default=None,
|
|
1555
|
-
description="Pool of the agent token",
|
|
1556
|
-
),
|
|
1557
|
-
]
|
|
1558
|
-
mode: Annotated[
|
|
1559
|
-
Optional[Literal["public", "private"]],
|
|
1560
|
-
PydanticField(
|
|
1561
|
-
default=None,
|
|
1562
|
-
description="Mode of the agent, public or private",
|
|
1563
|
-
),
|
|
1564
|
-
]
|
|
1565
|
-
fee_percentage: Annotated[
|
|
1566
|
-
Optional[Decimal],
|
|
1567
|
-
PydanticField(
|
|
1568
|
-
default=None,
|
|
1569
|
-
description="Fee percentage of the agent",
|
|
1570
|
-
),
|
|
1571
|
-
]
|
|
1572
|
-
owner: Annotated[
|
|
1573
|
-
Optional[str],
|
|
1574
|
-
PydanticField(
|
|
1575
|
-
default=None,
|
|
1576
|
-
description="Owner identifier of the agent, used for access control",
|
|
1577
|
-
max_length=50,
|
|
1578
|
-
json_schema_extra={
|
|
1579
|
-
"x-group": "internal",
|
|
1580
|
-
},
|
|
1581
|
-
),
|
|
1582
|
-
]
|
|
1583
|
-
upstream_id: Annotated[
|
|
1584
|
-
Optional[str],
|
|
1585
|
-
PydanticField(
|
|
1586
|
-
default=None,
|
|
1587
|
-
description="External reference ID for idempotent operations",
|
|
1588
|
-
max_length=100,
|
|
1589
|
-
json_schema_extra={
|
|
1590
|
-
"x-group": "internal",
|
|
1591
|
-
},
|
|
1592
|
-
),
|
|
1593
|
-
]
|
|
1594
|
-
upstream_extra: Annotated[
|
|
1595
|
-
Optional[Dict[str, Any]],
|
|
1596
|
-
PydanticField(
|
|
1597
|
-
default=None,
|
|
1598
|
-
description="Additional data store for upstream use",
|
|
1599
|
-
),
|
|
1600
|
-
]
|
|
1601
|
-
# AI part
|
|
1602
|
-
model: Annotated[
|
|
1603
|
-
str,
|
|
1604
|
-
PydanticField(
|
|
1605
|
-
description="AI model identifier to be used by this agent for processing requests. Available models: gpt-4o, gpt-4o-mini, deepseek-chat, deepseek-reasoner, grok-2, eternalai, reigent",
|
|
1606
|
-
),
|
|
1607
|
-
]
|
|
1608
|
-
# autonomous mode
|
|
1609
|
-
autonomous: Annotated[
|
|
1610
|
-
Optional[List[Dict[str, Any]]],
|
|
1611
|
-
PydanticField(
|
|
1612
|
-
default=None,
|
|
1613
|
-
description=("Autonomous agent configurations."),
|
|
1614
|
-
),
|
|
1615
|
-
]
|
|
1616
|
-
# agent examples
|
|
1617
|
-
example_intro: Annotated[
|
|
1618
|
-
Optional[str],
|
|
1619
|
-
PydanticField(
|
|
1620
|
-
default=None,
|
|
1621
|
-
description="Introduction for example interactions",
|
|
1622
|
-
),
|
|
1623
|
-
]
|
|
1624
|
-
examples: Annotated[
|
|
1625
|
-
Optional[List[AgentExample]],
|
|
1626
|
-
PydanticField(
|
|
1627
|
-
default=None,
|
|
1628
|
-
description="List of example prompts for the agent",
|
|
1629
|
-
),
|
|
1630
|
-
]
|
|
1631
|
-
# skills
|
|
1632
|
-
skills: Annotated[
|
|
1633
|
-
Optional[Dict[str, Any]],
|
|
1634
|
-
PydanticField(
|
|
1635
|
-
default=None,
|
|
1636
|
-
description="Dict of skills and their corresponding configurations",
|
|
1637
|
-
),
|
|
1638
|
-
]
|
|
1639
|
-
wallet_provider: Annotated[
|
|
1640
|
-
Optional[Literal["cdp", "readonly"]],
|
|
1641
|
-
PydanticField(
|
|
1642
|
-
default="cdp",
|
|
1643
|
-
description="Provider of the agent's wallet",
|
|
1644
|
-
),
|
|
1645
|
-
]
|
|
1646
|
-
network_id: Annotated[
|
|
1647
|
-
Optional[str],
|
|
1648
|
-
PydanticField(
|
|
1649
|
-
default="base-mainnet",
|
|
1650
|
-
description="Network identifier",
|
|
1651
|
-
),
|
|
1652
|
-
]
|
|
1653
|
-
cdp_network_id: Annotated[
|
|
1654
|
-
Optional[str],
|
|
1655
|
-
PydanticField(
|
|
1656
|
-
default="base-mainnet",
|
|
1657
|
-
description="Network identifier for CDP integration",
|
|
1658
|
-
),
|
|
1659
|
-
]
|
|
1660
|
-
# telegram entrypoint
|
|
1661
|
-
telegram_entrypoint_enabled: Annotated[
|
|
1662
|
-
Optional[bool],
|
|
1663
|
-
PydanticField(
|
|
1664
|
-
default=False,
|
|
1665
|
-
description="Whether the agent can play telegram bot",
|
|
1666
|
-
),
|
|
1667
|
-
]
|
|
1668
|
-
|
|
1669
1455
|
# data part
|
|
1670
1456
|
cdp_wallet_address: Annotated[
|
|
1671
1457
|
Optional[str], PydanticField(description="CDP wallet address for the agent")
|
|
@@ -1753,6 +1539,18 @@ class AgentResponse(BaseModel):
|
|
|
1753
1539
|
# Get base data from agent
|
|
1754
1540
|
data = agent.model_dump()
|
|
1755
1541
|
|
|
1542
|
+
# Hide the sensitive fields
|
|
1543
|
+
data.pop("purpose", None)
|
|
1544
|
+
data.pop("personality", None)
|
|
1545
|
+
data.pop("principles", None)
|
|
1546
|
+
data.pop("prompt", None)
|
|
1547
|
+
data.pop("prompt_append", None)
|
|
1548
|
+
data.pop("temperature", None)
|
|
1549
|
+
data.pop("frequency_penalty", None)
|
|
1550
|
+
data.pop("telegram_entrypoint_prompt", None)
|
|
1551
|
+
data.pop("telegram_config", None)
|
|
1552
|
+
data.pop("xmtp_entrypoint_prompt", None)
|
|
1553
|
+
|
|
1756
1554
|
# Filter sensitive fields from autonomous list
|
|
1757
1555
|
if data.get("autonomous"):
|
|
1758
1556
|
filtered_autonomous = []
|
|
@@ -1852,4 +1650,4 @@ class AgentResponse(BaseModel):
|
|
|
1852
1650
|
}
|
|
1853
1651
|
)
|
|
1854
1652
|
|
|
1855
|
-
return cls.
|
|
1653
|
+
return cls.model_construct(**data)
|