repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
Mirrored from https://github.com/yingqi-z20/Agent-libOS
stars
latest
clone command
git clone gitlawb://did:key:z6MkqRzA...RfoM/yingqi-z20-Agen...git clone gitlawb://did:key:z6MkqRzA.../yingqi-z20-Agen...d98dd2c9IPC1d ago| #1 | from __future__ import annotations |
| #2 | |
| #3 | from typing import Any |
| #4 | |
| #5 | from pydantic import BaseModel, Field |
| #6 | |
| #7 | from agent_libos.config import DEFAULT_CONFIG |
| #8 | from agent_libos.models import ObjectMetadata, ObjectPatch, ObjectType, ViewMode |
| #9 | from agent_libos.tools.base import SyncAgentTool, ToolContext, ToolErrorCode, ToolExecutionError, ToolPolicy |
| #10 | |
| #11 | _MEMORY_DEFAULTS = DEFAULT_CONFIG.memory |
| #12 | _TOOL_DEFAULTS = DEFAULT_CONFIG.tools |
| #13 | |
| #14 | |
| #15 | class CreateMemoryObjectArgs(BaseModel): |
| #16 | name: str | None = Field(default=None, description="Optional namespace-local object name.") |
| #17 | namespace: str | None = Field(default=None, description="Object Memory namespace. Defaults to this process namespace.") |
| #18 | type: str = Field(description="Agent libOS object type, for example summary, plan, observation, or artifact.") |
| #19 | payload: Any = Field(description="Structured payload to store.") |
| #20 | metadata: dict[str, Any] = Field(default_factory=dict) |
| #21 | immutable: bool = True |
| #22 | |
| #23 | |
| #24 | class CreateMemoryObjectOutput(BaseModel): |
| #25 | oid: str |
| #26 | namespace: str |
| #27 | name: str |
| #28 | type: str |
| #29 | |
| #30 | |
| #31 | class ReadMemoryObjectArgs(BaseModel): |
| #32 | name: str = Field(description="Namespace-local Object Memory name to read.") |
| #33 | namespace: str | None = Field(default=None, description="Object Memory namespace. Defaults to this process namespace.") |
| #34 | max_payload_chars: int = Field( |
| #35 | default=_TOOL_DEFAULTS.memory_payload_chars, |
| #36 | ge=1, |
| #37 | le=_TOOL_DEFAULTS.memory_payload_hard_limit_chars, |
| #38 | description="Maximum rendered payload chars.", |
| #39 | ) |
| #40 | |
| #41 | |
| #42 | class ReadMemoryObjectOutput(BaseModel): |
| #43 | oid: str |
| #44 | namespace: str |
| #45 | name: str |
| #46 | type: str |
| #47 | version: int |
| #48 | payload: Any |
| #49 | truncated: bool |
| #50 | |
| #51 | |
| #52 | class AppendMemoryObjectArgs(BaseModel): |
| #53 | name: str = Field(description="Namespace-local mutable Object Memory name to append to.") |
| #54 | namespace: str | None = Field(default=None, description="Object Memory namespace. Defaults to this process namespace.") |
| #55 | entry: Any = Field(description="Structured entry to append.") |
| #56 | list_field: str = Field( |
| #57 | default="entries", |
| #58 | description="Payload list field to append into when the object payload is a JSON object.", |
| #59 | ) |
| #60 | |
| #61 | |
| #62 | class AppendMemoryObjectOutput(BaseModel): |
| #63 | oid: str |
| #64 | namespace: str |
| #65 | name: str |
| #66 | version: int |
| #67 | appended: bool |
| #68 | list_field: str | None = None |
| #69 | length: int |
| #70 | |
| #71 | |
| #72 | class CreateMemoryNamespaceArgs(BaseModel): |
| #73 | namespace: str = Field(description="Namespace path to create, for example project/research or child-results.") |
| #74 | parent_namespace: str | None = Field( |
| #75 | default=None, |
| #76 | description="Parent namespace. Defaults to the path parent; top-level namespaces have no parent.", |
| #77 | ) |
| #78 | metadata: dict[str, Any] = Field(default_factory=dict) |
| #79 | |
| #80 | |
| #81 | class CreateMemoryNamespaceOutput(BaseModel): |
| #82 | namespace: str |
| #83 | parent_namespace: str | None |
| #84 | created: bool |
| #85 | |
| #86 | |
| #87 | class ListMemoryNamespaceArgs(BaseModel): |
| #88 | namespace: str | None = Field(default=None, description="Namespace to list. Defaults to this process namespace.") |
| #89 | |
| #90 | |
| #91 | class MemoryNamespaceObjectEntry(BaseModel): |
| #92 | oid: str |
| #93 | namespace: str |
| #94 | name: str |
| #95 | type: str |
| #96 | version: int |
| #97 | |
| #98 | |
| #99 | class MemoryNamespaceEntry(BaseModel): |
| #100 | namespace: str |
| #101 | parent_namespace: str | None |
| #102 | |
| #103 | |
| #104 | class ListMemoryNamespaceOutput(BaseModel): |
| #105 | namespace: str |
| #106 | objects: list[MemoryNamespaceObjectEntry] |
| #107 | namespaces: list[MemoryNamespaceEntry] |
| #108 | |
| #109 | |
| #110 | class CreateMemoryObjectTool(SyncAgentTool[CreateMemoryObjectArgs]): |
| #111 | name = "create_memory_object" |
| #112 | description = ( |
| #113 | "Create a typed object in Agent libOS Object Memory and attach it to this process MemoryView. " |
| #114 | "This is a Skills/Tools Layer wrapper over the memory manager." |
| #115 | ) |
| #116 | args_schema = CreateMemoryObjectArgs |
| #117 | output_schema = CreateMemoryObjectOutput |
| #118 | policy = ToolPolicy(side_effects=False, idempotent=False, timeout_s=_TOOL_DEFAULTS.standard_timeout_s) |
| #119 | tags = ["memory", "object"] |
| #120 | |
| #121 | def run(self, args: CreateMemoryObjectArgs, ctx: ToolContext) -> CreateMemoryObjectOutput: |
| #122 | runtime = ctx.runtime |
| #123 | if runtime is None: |
| #124 | raise ToolExecutionError("Runtime is unavailable.", code=ToolErrorCode.EXECUTION_ERROR) |
| #125 | metadata = ObjectMetadata( |
| #126 | title=args.metadata.get("title"), |
| #127 | summary=args.metadata.get("summary"), |
| #128 | tags=args.metadata.get("tags", []), |
| #129 | mime_type=args.metadata.get("mime_type"), |
| #130 | sensitivity=args.metadata.get("sensitivity", _MEMORY_DEFAULTS.metadata_sensitivity), |
| #131 | retention_policy=args.metadata.get("retention_policy", _MEMORY_DEFAULTS.metadata_retention_policy), |
| #132 | ) |
| #133 | handle = runtime.memory.create_object( |
| #134 | pid=ctx.pid, |
| #135 | object_type=ObjectType(args.type), |
| #136 | payload=args.payload, |
| #137 | metadata=metadata, |
| #138 | immutable=args.immutable, |
| #139 | name=args.name, |
| #140 | namespace=args.namespace, |
| #141 | ) |
| #142 | obj = runtime.memory.get_object(ctx.pid, handle) |
| #143 | process = runtime.process.get(ctx.pid) |
| #144 | if process.memory_view is None: |
| #145 | process.memory_view = runtime.memory.create_view(ctx.pid, [handle], mode=ViewMode.READ_ONLY) |
| #146 | elif all(existing.oid != handle.oid for existing in process.memory_view.roots): |
| #147 | process.memory_view.roots.append(handle) |
| #148 | runtime.store.update_process(process) |
| #149 | return CreateMemoryObjectOutput(oid=handle.oid, namespace=obj.namespace, name=obj.name, type=args.type) |
| #150 | |
| #151 | |
| #152 | class CreateMemoryNamespaceTool(SyncAgentTool[CreateMemoryNamespaceArgs]): |
| #153 | name = "create_memory_namespace" |
| #154 | description = ( |
| #155 | "Create an Object Memory namespace. Namespaces provide directory-like name scopes; " |
| #156 | "object capabilities still control object reads and writes." |
| #157 | ) |
| #158 | args_schema = CreateMemoryNamespaceArgs |
| #159 | output_schema = CreateMemoryNamespaceOutput |
| #160 | policy = ToolPolicy(side_effects=True, idempotent=False, timeout_s=_TOOL_DEFAULTS.standard_timeout_s) |
| #161 | tags = ["memory", "object", "namespace"] |
| #162 | |
| #163 | def run(self, args: CreateMemoryNamespaceArgs, ctx: ToolContext) -> CreateMemoryNamespaceOutput: |
| #164 | runtime = ctx.runtime |
| #165 | if runtime is None: |
| #166 | raise ToolExecutionError("Runtime is unavailable.", code=ToolErrorCode.EXECUTION_ERROR) |
| #167 | namespace = runtime.memory.create_namespace( |
| #168 | pid=ctx.pid, |
| #169 | namespace=args.namespace, |
| #170 | parent_namespace=args.parent_namespace, |
| #171 | metadata=args.metadata, |
| #172 | ) |
| #173 | return CreateMemoryNamespaceOutput( |
| #174 | namespace=namespace.namespace, |
| #175 | parent_namespace=namespace.parent_namespace, |
| #176 | created=True, |
| #177 | ) |
| #178 | |
| #179 | |
| #180 | class ListMemoryNamespaceTool(SyncAgentTool[ListMemoryNamespaceArgs]): |
| #181 | name = "list_memory_namespace" |
| #182 | description = ( |
| #183 | "List process-visible objects and child namespaces within an Object Memory namespace. " |
| #184 | "The list contains only objects the process can read." |
| #185 | ) |
| #186 | args_schema = ListMemoryNamespaceArgs |
| #187 | output_schema = ListMemoryNamespaceOutput |
| #188 | policy = ToolPolicy(side_effects=False, idempotent=True, timeout_s=_TOOL_DEFAULTS.standard_timeout_s) |
| #189 | tags = ["memory", "object", "namespace", "read"] |
| #190 | |
| #191 | def run(self, args: ListMemoryNamespaceArgs, ctx: ToolContext) -> ListMemoryNamespaceOutput: |
| #192 | runtime = ctx.runtime |
| #193 | if runtime is None: |
| #194 | raise ToolExecutionError("Runtime is unavailable.", code=ToolErrorCode.EXECUTION_ERROR) |
| #195 | listing = runtime.memory.list_namespace(ctx.pid, args.namespace) |
| #196 | objects = [ |
| #197 | MemoryNamespaceObjectEntry( |
| #198 | oid=obj.oid, |
| #199 | namespace=obj.namespace, |
| #200 | name=obj.name, |
| #201 | type=obj.type.value, |
| #202 | version=obj.version, |
| #203 | ) |
| #204 | for obj in listing["objects"] |
| #205 | ] |
| #206 | namespaces = [ |
| #207 | MemoryNamespaceEntry(namespace=namespace.namespace, parent_namespace=namespace.parent_namespace) |
| #208 | for namespace in listing["namespaces"] |
| #209 | ] |
| #210 | return ListMemoryNamespaceOutput( |
| #211 | namespace=listing["namespace"], |
| #212 | objects=objects, |
| #213 | namespaces=namespaces, |
| #214 | ) |
| #215 | |
| #216 | |
| #217 | class ReadMemoryObjectTool(SyncAgentTool[ReadMemoryObjectArgs]): |
| #218 | name = "read_memory_object" |
| #219 | description = ( |
| #220 | "Read a named Object Memory object. Name lookup does not grant authority; " |
| #221 | "the memory primitive still enforces object read capability." |
| #222 | ) |
| #223 | args_schema = ReadMemoryObjectArgs |
| #224 | output_schema = ReadMemoryObjectOutput |
| #225 | policy = ToolPolicy(side_effects=False, idempotent=True, timeout_s=_TOOL_DEFAULTS.standard_timeout_s) |
| #226 | tags = ["memory", "object", "read"] |
| #227 | |
| #228 | def run(self, args: ReadMemoryObjectArgs, ctx: ToolContext) -> ReadMemoryObjectOutput: |
| #229 | runtime = ctx.runtime |
| #230 | if runtime is None: |
| #231 | raise ToolExecutionError("Runtime is unavailable.", code=ToolErrorCode.EXECUTION_ERROR) |
| #232 | obj = runtime.memory.get_object_by_name(ctx.pid, args.name, namespace=args.namespace) |
| #233 | payload = obj.payload |
| #234 | rendered = repr(payload) |
| #235 | truncated = len(rendered) > args.max_payload_chars |
| #236 | if truncated: |
| #237 | payload = rendered[: args.max_payload_chars] |
| #238 | return ReadMemoryObjectOutput( |
| #239 | oid=obj.oid, |
| #240 | namespace=obj.namespace, |
| #241 | name=obj.name, |
| #242 | type=obj.type.value, |
| #243 | version=obj.version, |
| #244 | payload=payload, |
| #245 | truncated=truncated, |
| #246 | ) |
| #247 | |
| #248 | |
| #249 | class AppendMemoryObjectTool(SyncAgentTool[AppendMemoryObjectArgs]): |
| #250 | name = "append_memory_object" |
| #251 | description = ( |
| #252 | "Append a structured entry to a mutable named Object Memory object. " |
| #253 | "This is the preferred write pattern for LLM context objects because it preserves prompt-cache-friendly prefixes." |
| #254 | ) |
| #255 | args_schema = AppendMemoryObjectArgs |
| #256 | output_schema = AppendMemoryObjectOutput |
| #257 | policy = ToolPolicy(side_effects=True, idempotent=False, timeout_s=_TOOL_DEFAULTS.standard_timeout_s) |
| #258 | tags = ["memory", "object", "write", "append"] |
| #259 | |
| #260 | def run(self, args: AppendMemoryObjectArgs, ctx: ToolContext) -> AppendMemoryObjectOutput: |
| #261 | runtime = ctx.runtime |
| #262 | if runtime is None: |
| #263 | raise ToolExecutionError("Runtime is unavailable.", code=ToolErrorCode.EXECUTION_ERROR) |
| #264 | handle = runtime.memory.handle_for_name( |
| #265 | ctx.pid, |
| #266 | args.name, |
| #267 | rights=["read", "write"], |
| #268 | issued_by="append_memory_object_tool", |
| #269 | namespace=args.namespace, |
| #270 | ) |
| #271 | obj = runtime.memory.get_object(ctx.pid, handle) |
| #272 | payload = obj.payload |
| #273 | if isinstance(payload, dict): |
| #274 | values = payload.setdefault(args.list_field, []) |
| #275 | if not isinstance(values, list): |
| #276 | raise ToolExecutionError( |
| #277 | "Target payload field is not a list.", |
| #278 | code=ToolErrorCode.VALIDATION_ERROR, |
| #279 | details={"name": args.name, "list_field": args.list_field}, |
| #280 | ) |
| #281 | values.append(args.entry) |
| #282 | length = len(values) |
| #283 | list_field: str | None = args.list_field |
| #284 | elif isinstance(payload, list): |
| #285 | payload.append(args.entry) |
| #286 | length = len(payload) |
| #287 | list_field = None |
| #288 | else: |
| #289 | raise ToolExecutionError( |
| #290 | "Target object payload is not appendable.", |
| #291 | code=ToolErrorCode.VALIDATION_ERROR, |
| #292 | details={"name": args.name, "payload_type": type(payload).__name__}, |
| #293 | ) |
| #294 | runtime.memory.update_object(ctx.pid, handle, ObjectPatch(payload=payload)) |
| #295 | updated = runtime.memory.get_object(ctx.pid, handle) |
| #296 | return AppendMemoryObjectOutput( |
| #297 | oid=updated.oid, |
| #298 | namespace=updated.namespace, |
| #299 | name=updated.name, |
| #300 | version=updated.version, |
| #301 | appended=True, |
| #302 | list_field=list_field, |
| #303 | length=length, |
| #304 | ) |
| #305 |