Skip to main content

deepstrike_core/runtime/kernel/wire/
syscall.rs

1//! P1 syscall requests and their causation (spec §7.6).
2//!
3//! A syscall is **not** a sixth wire input class. It reaches the kernel one of exactly two ways,
4//! and in both the caller is derived from kernel-owned state rather than declared by the host:
5//!
6//! * the current operation's provider tool call — recognised while resolving the provider effect;
7//! * a child's request, attached to its `ChildCompleted` fact — the parent kernel derives the
8//!   caller from the attempt.
9//!
10//! There is no `AgentRequest { actor_id }`, and no SDK-side path that fills an actor in.
11
12use serde::{Deserialize, Serialize};
13
14use super::command::TaskUpdate;
15use super::root::{WorkflowNode, WorkflowSpec};
16use super::scalar::{AttemptId, CallId, EffectId, HandleId, TaskId};
17
18#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
19#[serde(tag = "kind", rename_all = "snake_case")]
20pub enum SyscallRequest {
21    SubmitWorkflow(SubmitWorkflowRequest),
22    AppendWorkflowNodes(AppendWorkflowNodesRequest),
23    ActivateSkill(ActivateSkillRequest),
24    /// The model's task update. Distinct from `HostCommand::UpdateTask` precisely because the
25    /// two have different authority.
26    UpdateTask(UpdateTaskRequest),
27    RequestMemoryWrite(RequestMemoryWriteRequest),
28    RequestMemoryQuery(RequestMemoryQueryRequest),
29    /// P3 handle page-in. Opposite in meaning to the host's `SeedKnowledge` command (DEC-9).
30    PageIn(PageInRequest),
31}
32
33#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
34#[serde(deny_unknown_fields)]
35pub struct SubmitWorkflowRequest {
36    pub spec: WorkflowSpec,
37}
38
39#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
40#[serde(deny_unknown_fields)]
41pub struct AppendWorkflowNodesRequest {
42    pub nodes: Vec<WorkflowNode>,
43}
44
45#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
46#[serde(deny_unknown_fields)]
47pub struct ActivateSkillRequest {
48    pub name: String,
49    /// Auto-deactivate after this many turns. `None` ⇒ until explicitly deactivated.
50    #[serde(default, skip_serializing_if = "Option::is_none")]
51    pub lease_turns: Option<u32>,
52}
53
54#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
55#[serde(deny_unknown_fields)]
56pub struct UpdateTaskRequest {
57    pub update: TaskUpdate,
58}
59
60#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
61#[serde(deny_unknown_fields)]
62pub struct RequestMemoryWriteRequest {
63    pub proposal: MemoryWriteProposal,
64}
65
66/// A **proposal**, not a record. It carries no tenant/namespace, no record id, no author or trust
67/// level, no timestamp and no session provenance: the kernel derives all of those from the
68/// operation's memory binding, the envelope's accepted time and the syscall causation.
69#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
70#[serde(deny_unknown_fields)]
71pub struct MemoryWriteProposal {
72    pub name: String,
73    pub kind: MemoryKind,
74    pub content: String,
75    #[serde(default, skip_serializing_if = "String::is_empty")]
76    pub description: String,
77    #[serde(default, skip_serializing_if = "Vec::is_empty")]
78    pub evidence_refs: Vec<String>,
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
82#[serde(rename_all = "snake_case")]
83pub enum MemoryKind {
84    User,
85    Feedback,
86    Project,
87    Reference,
88}
89
90#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
91#[serde(deny_unknown_fields)]
92pub struct RequestMemoryQueryRequest {
93    pub query: MemoryQueryProposal,
94}
95
96#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
97#[serde(deny_unknown_fields)]
98pub struct MemoryQueryProposal {
99    #[serde(default, skip_serializing_if = "String::is_empty")]
100    pub text: String,
101    #[serde(default, skip_serializing_if = "Vec::is_empty")]
102    pub kinds: Vec<MemoryKind>,
103    #[serde(default, skip_serializing_if = "Option::is_none")]
104    pub limit: Option<u32>,
105}
106
107#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
108#[serde(deny_unknown_fields)]
109pub struct PageInRequest {
110    /// Must already be reachable in the current P3 handle table.
111    pub handle_id: HandleId,
112}
113
114/// How the kernel derived the caller of a syscall. Never host-supplied.
115#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
116#[serde(tag = "kind", rename_all = "snake_case")]
117pub enum SyscallCausation {
118    /// A tool call inside the provider result the kernel is currently resolving.
119    ProviderTool(ProviderToolCausation),
120    /// A request a child attached to its completion fact.
121    ChildAttempt(ChildAttemptCausation),
122}
123
124#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
125#[serde(deny_unknown_fields)]
126pub struct ProviderToolCausation {
127    pub provider_effect_id: EffectId,
128    pub call_id: CallId,
129    pub task_id: TaskId,
130}
131
132#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
133#[serde(deny_unknown_fields)]
134pub struct ChildAttemptCausation {
135    pub task_id: TaskId,
136    pub attempt_id: AttemptId,
137    /// Position in the child's `parent_requests` list. Derived from that stable order — a host
138    /// never picks it.
139    pub request_seq: u32,
140}