Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,27 @@
## v0.8.38 - 2025-01-31
## v0.8.39 - 2026-01-04

### Features
- **Safe Smart Wallet Integration**: Implemented Safe smart wallet functionality with Privy wallet provider for enhanced security and multi-signature support
- **Agent Activity & Post Modules**: Added comprehensive agent activity and post modules with complete models, core logic, and unit tests
- **System Skills**: Introduced system skills for creating posts and activities, enabling agents to interact with the platform
- **Skill Call Agent**: Implemented skill call agent functionality with improved error handling and validation
- **Default System Skills**: System skills are now included by default for all agents

### Improvements
- **Unified Agent API Router**: Refactored auth and openai_compatible endpoints into a unified agent_api router for better organization
- **Better Error Handling**: Enhanced error messages and handling in call agent skill
- **Agent Post Skill**: Improved agent post skill functionality

### Testing
- Added comprehensive unit tests for template functions including `create_template_from_agent` and `render_agent`

### Maintenance
- Upgraded dependencies to latest versions
- Fixed various lint issues

**Full Changelog**: https://github.com/crestalnetwork/intentkit/compare/v0.8.38...v0.8.39

## v0.8.38 - 2025-12-31

### Features
- **Template System**: Added comprehensive agent template functionality
Expand All @@ -20,7 +43,7 @@

**Full Changelog**: https://github.com/crestalnetwork/intentkit/compare/v0.8.37...v0.8.38

## v0.8.37 - 2025-01-27
## v0.8.37 - 2025-12-27

### Features
- Frontend skill box display in chat interface
Expand All @@ -37,7 +60,7 @@

**Full Changelog**: https://github.com/crestalnetwork/intentkit/compare/v0.8.36...v0.8.37

## v0.8.35 - 2025-01-30
## v0.8.35 - 2025-11-30

### Features
- Add GPT-5.2 model with enhanced capabilities (1.75 input pricing, 14 output pricing)
Expand Down
8 changes: 8 additions & 0 deletions app/autonomous.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ async def schedule_agent_autonomous_tasks():

try:
# Schedule new job based on minutes or cron
# Default has_memory to True if not set (backward compatibility)
task_has_memory = (
autonomous.has_memory
if autonomous.has_memory is not None
else True
)
if autonomous.cron:
logger.info(
f"Scheduling cron task {task_id} with cron: {autonomous.cron}"
Expand All @@ -121,6 +127,7 @@ async def schedule_agent_autonomous_tasks():
agent.owner,
autonomous.id,
autonomous.prompt,
task_has_memory,
],
replace_existing=True,
)
Expand All @@ -137,6 +144,7 @@ async def schedule_agent_autonomous_tasks():
agent.owner,
autonomous.id,
autonomous.prompt,
task_has_memory,
],
minutes=autonomous.minutes,
replace_existing=True,
Expand Down
72 changes: 71 additions & 1 deletion app/entrypoints/autonomous.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,49 @@

from epyxid import XID

from intentkit.core.agent_activity import create_agent_activity
from intentkit.core.chat import clear_thread_memory
from intentkit.core.client import execute_agent
from intentkit.models.agent_activity import AgentActivityCreate
from intentkit.models.chat import AuthorType, ChatMessageCreate

logger = logging.getLogger(__name__)


async def run_autonomous_task(
agent_id: str, agent_owner: str, task_id: str, prompt: str
agent_id: str,
agent_owner: str,
task_id: str,
prompt: str,
has_memory: bool = True,
):
"""
Run a specific autonomous task for an agent.

Args:
agent_id: The ID of the agent
agent_owner: The owner of the agent
task_id: The ID of the autonomous task
prompt: The autonomous prompt to execute
has_memory: Whether to retain conversation memory between runs.
If False, clears thread memory before execution.
"""
logger.info(f"Running autonomous task {task_id} for agent {agent_id}")

try:
# Run the autonomous action
chat_id = f"autonomous-{task_id}"

# Clear thread memory if has_memory is False
if not has_memory:
try:
_ = await clear_thread_memory(agent_id, chat_id)
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The underscore assignment pattern is used here, but the return value from clear_thread_memory is not used anywhere. While this is valid Python, it's more idiomatic to simply call the function without assignment when the return value is intentionally unused. Consider changing to: await clear_thread_memory(agent_id, chat_id)

Suggested change
_ = await clear_thread_memory(agent_id, chat_id)
await clear_thread_memory(agent_id, chat_id)

Copilot uses AI. Check for mistakes.
logger.debug(
f"Cleared thread memory for task {task_id} (has_memory=False)"
)
except Exception as e:
# Log the error but continue with execution
logger.warning(f"Failed to clear thread memory for task {task_id}: {e}")
message = ChatMessageCreate(
id=str(XID()),
agent_id=agent_id,
Expand All @@ -43,7 +64,56 @@ async def run_autonomous_task(
f"Task {task_id} completed: " + "\n".join(str(m) for m in resp),
extra={"aid": agent_id},
)

# Check response and create error activity if needed
if not resp:
try:
activity = AgentActivityCreate(
agent_id=agent_id,
text="Unexpected result: empty response",
)
_ = await create_agent_activity(activity)
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The underscore assignment pattern is used here, but the return value from create_agent_activity is not used anywhere. While this is valid Python, it's more idiomatic to simply call the function without assignment when the return value is intentionally unused. Consider changing to: await create_agent_activity(activity)

Copilot uses AI. Check for mistakes.
except Exception as e:
logger.warning(
f"Failed to create error activity for task {task_id}: {e}",
extra={"aid": agent_id},
)
else:
last_msg = resp[-1]
error_text = None

if last_msg.author_type == AuthorType.AGENT:
pass # Success, do nothing
elif last_msg.author_type == AuthorType.SYSTEM:
error_text = f"Task execution error: {last_msg.message}"
else:
Comment on lines +85 to +89
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pass statement with a comment is not very meaningful and could be removed. The if-elif-else structure would be clearer without this branch, or the comment could be more descriptive. Consider restructuring to only check for error conditions without the pass statement.

Suggested change
if last_msg.author_type == AuthorType.AGENT:
pass # Success, do nothing
elif last_msg.author_type == AuthorType.SYSTEM:
error_text = f"Task execution error: {last_msg.message}"
else:
if last_msg.author_type == AuthorType.SYSTEM:
error_text = f"Task execution error: {last_msg.message}"
elif last_msg.author_type != AuthorType.AGENT:

Copilot uses AI. Check for mistakes.
error_text = "Unexpected return error"
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message "Unexpected return error" is vague and doesn't provide useful context about what went wrong. Consider including more details such as the actual author_type value that was encountered to help with debugging. For example: "Unexpected author type in response: {last_msg.author_type}"

Suggested change
error_text = "Unexpected return error"
error_text = f"Unexpected author type in response: {last_msg.author_type}"

Copilot uses AI. Check for mistakes.

if error_text:
try:
activity = AgentActivityCreate(
agent_id=agent_id,
text=error_text,
)
_ = await create_agent_activity(activity)
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The underscore assignment pattern is used here, but the return value from create_agent_activity is not used anywhere. While this is valid Python, it's more idiomatic to simply call the function without assignment when the return value is intentionally unused. Consider changing to: await create_agent_activity(activity)

Copilot uses AI. Check for mistakes.
except Exception as e:
logger.warning(
f"Failed to create error activity for task {task_id}: {e}",
extra={"aid": agent_id},
)

except Exception as e:
logger.error(
f"Error in autonomous task {task_id} for agent {agent_id}: {str(e)}"
)
try:
activity = AgentActivityCreate(
agent_id=agent_id,
text=f"Autonomous task exception: {str(e)}",
)
_ = await create_agent_activity(activity)
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The underscore assignment pattern is used here, but the return value from create_agent_activity is not used anywhere. While this is valid Python, it's more idiomatic to simply call the function without assignment when the return value is intentionally unused. Consider changing to: await create_agent_activity(activity)

Copilot uses AI. Check for mistakes.
except Exception as activity_error:
logger.warning(
f"Failed to create exception activity for task {task_id}: {activity_error}",
extra={"aid": agent_id},
)
10 changes: 10 additions & 0 deletions intentkit/models/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,16 @@ class AgentAutonomous(BaseModel):
},
),
]
has_memory: Annotated[
bool | None,
PydanticField(
default=True,
description="Whether to retain conversation memory between autonomous runs. If False, thread memory is cleared before each run.",
json_schema_extra={
"x-group": "autonomous",
},
),
]

@field_validator("id")
@classmethod
Expand Down
7 changes: 7 additions & 0 deletions intentkit/models/agent_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,13 @@
"description": "Turn automation on/off",
"default": false,
"x-group": "autonomous"
},
"has_memory": {
"title": "Has Memory",
"type": "boolean",
"description": "Whether to retain conversation memory between autonomous runs. If disabled, thread memory is cleared before each run.",
"default": true,
"x-group": "autonomous"
}
},
"required": [
Expand Down
6 changes: 6 additions & 0 deletions intentkit/skills/system/add_autonomous_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ class AddAutonomousTaskInput(BaseModel):
description="Cron expression for scheduling operations, mutually exclusive with minutes",
)
prompt: str = Field(description="Special prompt used during autonomous operation")
has_memory: bool | None = Field(
default=True,
description="Whether to retain conversation memory between autonomous runs. If False, thread memory is cleared before each run.",
)


class AddAutonomousTaskOutput(BaseModel):
Expand Down Expand Up @@ -57,6 +61,7 @@ async def _arun(
minutes: int | None = None,
cron: str | None = None,
prompt: str = "",
has_memory: bool | None = True,
**kwargs,
) -> AddAutonomousTaskOutput:
"""Add an autonomous task to the agent.
Expand All @@ -82,6 +87,7 @@ async def _arun(
cron=cron,
prompt=prompt,
enabled=True,
has_memory=has_memory,
)

created_task = await agent.add_autonomous_task(task)
Expand Down
8 changes: 8 additions & 0 deletions intentkit/skills/system/edit_autonomous_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ class EditAutonomousTaskInput(BaseModel):
enabled: bool | None = Field(
default=None, description="Whether the autonomous task is enabled"
)
has_memory: bool | None = Field(
default=None,
description="Whether to retain conversation memory between autonomous runs. If False, thread memory is cleared before each run.",
)


class EditAutonomousTaskOutput(BaseModel):
Expand Down Expand Up @@ -65,6 +69,7 @@ async def _arun(
cron: str | None = None,
prompt: str | None = None,
enabled: bool | None = None,
has_memory: bool | None = None,
**kwargs,
) -> EditAutonomousTaskOutput:
"""Edit an autonomous task for the agent.
Expand All @@ -77,6 +82,7 @@ async def _arun(
cron: Cron expression (mutually exclusive with minutes)
prompt: Special prompt for autonomous operation
enabled: Whether the task is enabled
has_memory: Whether to retain memory between runs
config: Runtime configuration containing agent context

Returns:
Expand Down Expand Up @@ -104,6 +110,8 @@ async def _arun(
task_updates["prompt"] = prompt
if enabled is not None:
task_updates["enabled"] = enabled
if has_memory is not None:
task_updates["has_memory"] = has_memory

updated_task = await agent.update_autonomous_task(task_id, task_updates)

Expand Down
Loading