@kmlckj/licos-ai-cli 1.4.0 → 1.4.1

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.
@@ -33,7 +33,8 @@
33
33
  - 普通文件、上传下载和聊天附件按当前用户、会话隔离;路径相对会话目录,技能资源共享只读。办公文件解析和生成按项目需求注册为业务工具。
34
34
  - 平台 `upload_file` 附件块中的 HTTP(S) URL 或 base64 data URL 由运行时自动落地,不需要项目重复实现下载。模型根据 `status: saved` 和本地路径使用 `read_file` 读取文本;失败时说明错误,不读取同名旧文件。普通文本中的 URL 不会自动下载。
35
35
  - 普通链接按任务需要调用内置 `download_file(url, path)`,成功后使用返回的 `file_path`。生成文件先核对,再调用内置 `upload_file(path)`,用成功结果的完整 `url` 返回 Markdown 下载链接;上传失败说明错误,不能只交付本地路径或虚构链接。
36
- - 修改业务提示词时保留技能按需读取、附件成功/失败处理、文件会话范围、内置上传下载和真实下载链接的指导。文本读取工具不负责解析 PDF、Word、Excel 等二进制文件。
37
- - 历史由请求的 `messages` 提供,默认不建立跨请求内存会话;40 条消息是按完整轮次裁剪的软上限,不是固定 20 轮。文件跨请求复用需同一用户使用相同 `session_id`。
36
+ - 修改业务提示词时只描述项目业务角色和额外能力;内置工具说明由运行时按实际启用集合生成。文本读取工具不负责解析 PDF、Word、Excel 等二进制文件。
37
+ - `input + session_id` 按认证用户、项目及环境隔离,当前进程保留最近 3 个已完成问答;显式 `messages` 沿用调用方历史协议。重启会丢失短期记忆,多副本需要会话固定路由。
38
+ - 顶层 `harness` 配置计划、上下文预算、执行上限、工具禁用/确认和结果校验。需要持久历史时先确认用户需求,再用 CLI 迁移项目数据库并按用户隔离。
38
39
  - 输入支持 `input`、多轮 `messages`、`event` 及组合,保留附件和多模态内容。
39
40
  - `tests/agent_cases.json` 维护可重复的输入及业务工具验收;生成或修改后对已有预览执行 `bash scripts/runtime.sh -m verify`,失败则修复后重验。
@@ -62,7 +62,7 @@ Body 可以同时带 `attachments`、`files`、`references` 等业务字段;
62
62
 
63
63
  结构化事件使用顶层 `event` 对象,例如 `{"event":{"type":"test.observation","source":"MANUAL_REPLAY","value":42}}`。可以同时传 `input` 和 `event`,两者都会进入模型;`input` 与最后一条用户消息内容相同则只处理一次。事件来源必须据实填写,人工回放不能标成实时事件。
64
64
 
65
- 默认图通过平台模型与已注册工具循环执行,使用 `licos_agent_runtime.project_agent.build_project_agent`,传入本次运行的 `ctx`。调用方传入多轮 `messages`,模板不使用跨请求共享的内存会话。长对话按完整用户轮次裁剪,当前工具调用及返回始终成对保留。
65
+ 默认图通过平台模型与已注册工具循环执行,使用 `licos_agent_runtime.project_agent.build_project_agent`,传入本次运行的 `ctx`。`input + session_id` 按认证用户隔离,在当前进程保留最近 3 个已完成问答;显式传入 `messages` 时只使用调用方历史。进程重启会清空短期记忆,多副本需单实例或会话固定路由。
66
66
 
67
67
  默认工具包括 `read_file`、`write_file`、`glob_file`、`list_files`、`download_file`、`upload_file`、`list_skills`、`read_skill`,无需加入业务 `TOOLS` 或配置 `tools`。文件工具按当前用户和 `session_id` 隔离,路径相对会话目录;同一会话可继续读取先前生成的文件。HTTP 请求使用平台用户 Bearer 令牌确认身份,普通文件和上传下载不能跨会话访问。
68
68
 
@@ -123,9 +123,11 @@ Body 可以同时带 `attachments`、`files`、`references` 等业务字段;
123
123
  - `config`:模型、温度、超时、thinking 等运行参数;`model: "auto"` 表示使用平台默认模型
124
124
  - `sp`:系统提示词
125
125
  - `up`:用户提示补充
126
- - `tools`:业务工具名称列表,新增或删除业务工具时同步维护;运行时默认注册的六个内置工具不列入此数组
126
+ - `tools`:业务工具名称列表,新增或删除业务工具时同步维护;运行时的八个内置工具不列入此数组
127
+ - `harness`:版本 1 的短期记忆、计划、模型上下文预算、调用限制、工具策略、结果校验和思考内容透传;配置修改从下一任务生效
128
+ - `harness.thinking.forward_to_frontend`:默认 `false`。开启时,模型返回的思考内容以独立流事件发送到预览页和 SDK 页面,思考完成自动折叠;与 `config.thinking` 的模型思考开关分别控制
127
129
 
128
- 模板 `sp` 已包含技能调用、附件读取及失败处理、会话文件范围、按需文档处理和真实下载链接要求。`build_project_agent` 还会追加运行时能力说明及已发现技能的名称、简介;技能全文通过工具按需读取。修改业务身份或输出要求时保留这些使用约定。
130
+ 模板 `sp` 保存业务角色和真实结果要求。`build_project_agent` 按实际启用的工具追加文件及技能能力说明;禁用工具不会暴露给模型。模型上下文窗口来自平台目录,缺少窗口信息会返回配置错误。
129
131
 
130
132
  ## 项目上下文
131
133
 
@@ -145,7 +147,7 @@ Body 可以同时带 `attachments`、`files`、`references` 等业务字段;
145
147
  bash scripts/runtime.sh -m verify --cases tests/agent_cases.json --report .tmp/agent-verification.json
146
148
  ```
147
149
 
148
- 命令检查导入、图输入、工具注册,并对每个用例调用 HTTP 与 SSE,核对真实模型调用、工具调用、输入证据和运行用量。业务查询用例需要增加 `required_tools`,例如 `["query_current"]`;`model_contains` 用于检查输入文本或事件字段进入模型。报告保留 run_id,失败返回非零退出码。默认用例只验证通用输入,不能替代业务证据验收。
150
+ 命令检查导入、图输入、工具注册,并对每个用例调用 HTTP 与 SSE,核对真实模型调用、工具调用、输入证据和运行用量。相同 `session_group` 的用例复用会话,检查跨请求短期记忆;业务查询用例可增加 `required_tools`。报告保留 run_id,失败返回非零退出码。
149
151
 
150
152
  预览、本地运行和验收共用 `scripts/runtime.sh`:显式设置 `PYTHON_BIN` 时使用该解释器,否则使用已创建的项目 `.venv`,全局安装模式使用 `python`。选定环境损坏会直接失败。
151
153
 
@@ -7,7 +7,26 @@
7
7
  "timeout": 600,
8
8
  "thinking": "auto"
9
9
  },
10
- "sp": "你是一个 LICOS 智能体,根据用户需求和可用工具完成任务。任务匹配内置技能时,先用 read_skill 读取 SKILL.md,再按需读取技能引用的文件或子目录。普通文件使用 list_files、glob_file、read_file、write_file,路径相对当前用户的当前会话目录,生成结果放在 assets/ 下。上传附件由运行时自动保存;看到 status: saved 后,使用返回的 local file path 读取文本,无需再次下载,预览内容不一定完整。附件保存失败会由运行时直接终止本次请求并返回错误,不使用同名旧文件替代本次附件。任务需要读取普通文本中的 HTTP(S) 文件链接时,使用内置 download_file(url, path) 下载到当前会话,再按返回的 file_path 读取。read_file 只读 UTF-8 文本;PDF、Word、Excel 等解析和生成按项目已注册的业务工具执行。修改文件前先读取,写入后核对。向用户交付生成文件时,调用内置 upload_file(path),上传成功后使用工具返回的完整 url 提供 Markdown 下载链接,链接有效期以 expiresAt 为准;本地路径不是下载链接。上传失败则说明具体错误,不声称交付成功、不编造链接。工具报错后根据错误修正参数或调整步骤,不编造文件内容、执行结果或业务数据。",
10
+ "sp": "你是一个 LICOS 智能体,根据用户需求和当前可用工具完成任务。修改文件前先读取,写入后核对。工具报错后根据错误修正参数或调整步骤,不编造文件内容、执行结果或业务数据。",
11
11
  "up": "",
12
- "tools": []
12
+ "tools": [],
13
+ "harness": {
14
+ "version": 1,
15
+ "memory": { "enabled": true, "recent_turns": 3, "idle_ttl_seconds": 3600 },
16
+ "planning": { "mode": "auto" },
17
+ "context": {
18
+ "input_budget_ratio": 0.7,
19
+ "compaction_enabled": true,
20
+ "compact_at_ratio": 0.8,
21
+ "compact_to_ratio": 0.55
22
+ },
23
+ "execution": {
24
+ "max_model_calls": 30,
25
+ "max_tool_calls": 60,
26
+ "max_duration_seconds": 900
27
+ },
28
+ "tool_policy": { "disabled": [], "require_approval": [] },
29
+ "verification": { "mode": "tool_evidence", "max_repair_attempts": 1 },
30
+ "thinking": { "forward_to_frontend": false }
31
+ }
13
32
  }
@@ -4,8 +4,8 @@ version = "0.1.0"
4
4
  description = "LICOS LangGraph agent project"
5
5
  requires-python = ">=3.12"
6
6
  dependencies = [
7
- "licos-agent-runtime>=0.3.0",
8
- "licos-dev-sdk>=0.4.8",
7
+ "licos-agent-runtime>=0.3.1",
8
+ "licos-dev-sdk>=0.4.9",
9
9
  ]
10
10
 
11
11
  [tool.uv]
@@ -1,2 +1,2 @@
1
- licos-agent-runtime>=0.3.0
2
- licos-dev-sdk>=0.4.8
1
+ licos-agent-runtime>=0.3.1
2
+ licos-dev-sdk>=0.4.9
@@ -1,27 +1,57 @@
1
1
  from __future__ import annotations
2
2
 
3
- import json
4
3
  from typing import Any
5
4
 
6
5
  from licos_agent_runtime.agent_graph import validate_tool_registry
7
6
  from licos_agent_runtime.graph_loader import project_root
7
+ from licos_agent_runtime.harness_config import load_agent_project_config
8
+ from licos_agent_runtime.harness_execution import HarnessRun
9
+ from licos_agent_runtime.harness_verification import ProjectVerifier
8
10
  from licos_agent_runtime.project_agent import build_project_agent
9
- from licos_dev_sdk import create_chat_openai
11
+ from licos_dev_sdk import create_chat_openai, resolve_llm_endpoint
10
12
 
11
13
  from tools import TOOLS
12
14
 
13
15
  AGENT_CONFIG_PATH = "config/agent_llm_config.json"
16
+ PROJECT_VERIFIER: ProjectVerifier | None = None
14
17
 
15
18
 
16
19
  def create_agent(_ctx: Any = None) -> Any:
17
20
  root = project_root()
18
- settings = json.loads((root / AGENT_CONFIG_PATH).read_text(encoding="utf-8"))
21
+ snapshot = _ctx.metadata.get("agent_project_config") if _ctx is not None else None
22
+ if snapshot is None:
23
+ snapshot = load_agent_project_config(root)
24
+ if snapshot is None:
25
+ raise ValueError(f"Missing AGENT project config: {AGENT_CONFIG_PATH}")
26
+ settings = snapshot.raw
19
27
  validate_tool_registry(TOOLS, settings["tools"])
20
28
  model_options = dict(settings["config"])
21
29
  thinking = model_options.pop("thinking", "auto")
22
30
  if thinking != "auto":
23
31
  model_options["extra_body"] = {"thinking": {"type": thinking}}
24
- model = create_chat_openai(**model_options)
32
+ model = create_chat_openai(
33
+ **model_options,
34
+ preserve_reasoning=bool(snapshot.harness and snapshot.harness.thinking.forward_to_frontend),
35
+ )
36
+ harness_run = None
37
+ if snapshot.harness is not None:
38
+ endpoint = resolve_llm_endpoint(
39
+ model=model_options.get("model"), model_group=model_options.get("model_group", "text")
40
+ )
41
+ if endpoint.context_length is None:
42
+ raise ValueError(f"Model catalog is missing contextLength for {endpoint.model}")
43
+ reserve = model_options.get("max_completion_tokens") or model_options.get("max_tokens")
44
+ if not isinstance(reserve, int):
45
+ raise ValueError("AGENT Harness needs config.max_completion_tokens for the output reservation")
46
+ harness_run = HarnessRun(
47
+ snapshot.harness, endpoint.context_length, reserve, input_limit=endpoint.max_input_length
48
+ )
49
+ if _ctx is not None:
50
+ _ctx.metadata["agent_harness_run"] = harness_run
25
51
  prompt = "\n\n".join((settings["sp"], settings["up"]))
26
- # History comes from the platform's messages input, without shared memory.
27
- return build_project_agent(model, TOOLS, system_prompt=prompt, root=root, ctx=_ctx, config_path=AGENT_CONFIG_PATH)
52
+ return build_project_agent(
53
+ model, TOOLS, system_prompt=prompt, root=root, ctx=_ctx,
54
+ config_path=AGENT_CONFIG_PATH, harness=snapshot.harness, harness_run=harness_run,
55
+ verifier=PROJECT_VERIFIER,
56
+ approvals=_ctx.metadata.get("agent_approvals") if _ctx is not None else None,
57
+ )
@@ -3,5 +3,10 @@
3
3
  {"name": "messages", "payload": {"messages": [{"role": "user", "content": "请解释消息输入。"}]}, "model_contains": ["解释消息输入"]},
4
4
  {"name": "input+messages", "payload": {"input": "请解释消息输入。", "messages": [{"role": "user", "content": "请解释消息输入。"}]}, "model_contains": ["解释消息输入"]},
5
5
  {"name": "event", "payload": {"event": {"type": "test.observation", "source": "MANUAL_REPLAY", "value": 42}}, "model_contains": ["MANUAL_REPLAY", "42"]},
6
- {"name": "input+event", "payload": {"input": "解释这条测试事件。", "event": {"type": "test.observation", "source": "MANUAL_REPLAY", "value": 42}}, "model_contains": ["解释这条测试事件", "MANUAL_REPLAY", "42"]}
6
+ {"name": "input+event", "payload": {"input": "解释这条测试事件。", "event": {"type": "test.observation", "source": "MANUAL_REPLAY", "value": 42}}, "model_contains": ["解释这条测试事件", "MANUAL_REPLAY", "42"]},
7
+ {"name": "memory-turn-1", "session_group": "recent-turns", "payload": {"input": "这是第一轮测试标记:ALPHA。请简短回答。"}, "model_contains": ["ALPHA"]},
8
+ {"name": "memory-turn-2", "session_group": "recent-turns", "payload": {"input": "这是第二轮测试标记:BETA。请简短回答。"}, "model_contains": ["ALPHA", "BETA"]},
9
+ {"name": "memory-turn-3", "session_group": "recent-turns", "payload": {"input": "这是第三轮测试标记:GAMMA。请简短回答。"}, "model_contains": ["ALPHA", "BETA", "GAMMA"]},
10
+ {"name": "memory-turn-4", "session_group": "recent-turns", "payload": {"input": "这是第四轮测试标记:DELTA。请简短回答。"}, "model_contains": ["ALPHA", "BETA", "GAMMA", "DELTA"]},
11
+ {"name": "memory-turn-5", "session_group": "recent-turns", "payload": {"input": "这是第五轮测试标记:EPSILON。请简短回答。"}, "model_contains": ["BETA", "GAMMA", "DELTA", "EPSILON"], "model_not_contains": ["ALPHA"]}
7
12
  ]
@@ -4,8 +4,8 @@ version = "0.1.0"
4
4
  description = "LICOS LangGraph workflow project"
5
5
  requires-python = ">=3.12"
6
6
  dependencies = [
7
- "licos-agent-runtime>=0.3.0",
8
- "licos-dev-sdk>=0.4.8",
7
+ "licos-agent-runtime>=0.3.1",
8
+ "licos-dev-sdk>=0.4.9",
9
9
  ]
10
10
 
11
11
  [tool.uv]
@@ -1,2 +1,2 @@
1
- licos-agent-runtime>=0.3.0
2
- licos-dev-sdk>=0.4.8
1
+ licos-agent-runtime>=0.3.1
2
+ licos-dev-sdk>=0.4.9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kmlckj/licos-ai-cli",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "LICOS AI coding workspace CLI - project template engine and dev tools",
5
5
  "license": "MIT",
6
6
  "author": "kmlckj",