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
10 changes: 5 additions & 5 deletions argus/life/supervisor/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1817,9 +1817,9 @@ def _continuation_line(self, item_id: str, chinese: bool) -> str:
pending = []
if not pending:
return (
"计划里暂时没有下一项,Planner 正在决定接下来做什么。"
"计划里暂时没有下一项,正在考虑接下来做什么。"
if chinese
else "Nothing is queued yet; the Planner is deciding what comes next."
else "Nothing is queued yet; the next step is being considered."
)
next_title = " ".join(str(pending[0].title or "").split()) or (
"下一项" if chinese else "the next item"
Expand Down Expand Up @@ -2135,11 +2135,11 @@ def _message_id(legacy: str) -> str:
)
elif overall_complete and independent_review_required and review == "done":
continuation = (
"独立 Reviewer 已复核本轮产出,未发现阻断问题。"
"本次结果已由独立审阅者检查,未发现需要先修正的问题。"
if chinese
else (
"An independent Reviewer reviewed this run's output and "
"found no blocking issues."
"An independent reader checked this result and "
"found no issues that need fixing before proceeding."
)
)
elif str(outcome.get("stage_certification") or "").strip() == "deferred":
Expand Down
4 changes: 2 additions & 2 deletions argus/release_manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"package_version": "0.1.8",
"release_id": "0.1.8+901a92ac03f54664",
"release_id": "0.1.8+057b2aeae2b5e64e",
"schema_version": 1,
"source_digest": "901a92ac03f54664634bf33d57067cca393e7039321795e2fdcffc41378aa28a"
"source_digest": "057b2aeae2b5e64e0118bc9559681345bbc0b5bb4c56420f9f5fa34617a07c67"
}
5 changes: 4 additions & 1 deletion argus/roles/prompts/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@
_USER_FACING_STYLE = (
RESEARCHER_VOICE + "\n\n"
"Lead with the answer in plain language, and match the depth, tone, and detail the "
"operator's request calls for. Mention evidence when it matters; leave out internal "
"operator's request calls for. Do not assume research expertise; explain a "
"necessary unfamiliar term when first used and say what the result means "
"for the person. Give professional detail when requested, without changing "
"numbers, sources or uncertainty. Mention evidence when it matters; leave out internal "
"exchanges between roles and the sequence of tool calls. If work cannot proceed, "
"say why and what happens next. "
"Ask one clear question only when the operator must decide. Satisfy the stated "
Expand Down
21 changes: 14 additions & 7 deletions argus/roles/prompts/voice.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@

Every role ends its turn with a few lines the code parses. Everything else it
writes for a person, whether a reason, a next step, a note, a question, or a
heading, should read as a thoughtful researcher writes to a colleague. This
heading, should be understandable without knowing Argus or the field. This
paragraph is shared by the Manager, Planner, Engineer, and Reviewer prompts so
that the standard is one standard. See ``docs/how-argus-speaks.md``.
"""
from __future__ import annotations

RESEARCHER_VOICE = (
"## How to write for the person who will read this\n"
"Write to a colleague in the person's language: precise, natural, plain. "
"Name what you are checking or changing and why; lead results with what "
"was found, then evidence, limits and next steps. Explain unfamiliar terms "
"when needed. If work stops, say the cause, its effect and whether work "
"Write in the person's language: precise, natural, plain. By default assume "
"an ordinary reader, not a research colleague or someone who knows Argus. "
"Lead with the answer and what it means for the person; then include the "
"evidence and limits that matter. Name what you are checking or changing "
"and why. Explain necessary unfamiliar terms in everyday words at first use. "
"Offer next steps only when the person needs to act. Match depth to the "
"request: answer simple questions directly without a forced template, and "
"retain precise terms and professional detail when asked. Preserve numbers, "
"sources and uncertainty; simpler language must not change the conclusion. "
"If work stops, say the cause, its effect and whether work "
"will continue or needs the person to act. Never invent progress, completion "
"or retries. Call files files and results results. Keep internal role names, "
"rounds, field names, status tokens, tool arguments and workflow terms "
Expand All @@ -28,8 +34,9 @@
# the brief must state its own ban on protocol labels next to the prose field
# it defines, the way the front-door prompt does for REPLY.
RESEARCHER_VOICE_BRIEF = (
"Write plainly in their language; state the work, result and next step "
"without internal tokens."
"Write plainly for an ordinary reader in their language; lead with the "
"answer and its meaning, explain necessary terms, preserve uncertainty, "
"and give a next step only when they need to act, without internal tokens."
)

__all__ = ["RESEARCHER_VOICE", "RESEARCHER_VOICE_BRIEF"]
17 changes: 17 additions & 0 deletions argus/tools/resource_ledger/resource_ledger_status.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,19 @@
}
},
"$defs": {
"ResourceDeviceStatus": {
"type": "object",
"additionalProperties": false,
"required": ["index", "name", "total_memory_mib", "used_memory_mib", "utilization_percent", "reserved"],
"properties": {
"index": {"type": "string"},
"name": {"type": "string"},
"total_memory_mib": {"type": "integer", "minimum": 0},
"used_memory_mib": {"type": "integer", "minimum": 0},
"utilization_percent": {"type": "number", "minimum": 0, "maximum": 100},
"reserved": {"type": "boolean"}
}
},
"ResourceAcceleratorStatus": {
"type": "object",
"additionalProperties": false,
Expand Down Expand Up @@ -68,6 +81,10 @@
},
"detail": {
"type": "string"
},
"devices": {
"type": "array",
"items": {"$ref": "#/$defs/ResourceDeviceStatus"}
}
}
},
Expand Down
24 changes: 22 additions & 2 deletions argus/tools/resource_ledger/status_schema_generated.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,25 @@
'items': {'$ref': '#/$defs/ResourceAcceleratorStatus'}},
'holders': {'type': 'array', 'items': {'$ref': '#/$defs/ResourceHolderStatus'}},
'queue': {'type': 'array', 'items': {'$ref': '#/$defs/ResourceQueueStatus'}}},
'$defs': {'ResourceAcceleratorStatus': {'type': 'object',
'$defs': {'ResourceDeviceStatus': {'type': 'object',
'additionalProperties': False,
'required': ['index',
'name',
'total_memory_mib',
'used_memory_mib',
'utilization_percent',
'reserved'],
'properties': {'index': {'type': 'string'},
'name': {'type': 'string'},
'total_memory_mib': {'type': 'integer',
'minimum': 0},
'used_memory_mib': {'type': 'integer',
'minimum': 0},
'utilization_percent': {'type': 'number',
'minimum': 0,
'maximum': 100},
'reserved': {'type': 'boolean'}}},
'ResourceAcceleratorStatus': {'type': 'object',
'additionalProperties': False,
'required': ['kind', 'status', 'device_count', 'detail'],
'properties': {'kind': {'type': 'string'},
Expand All @@ -27,7 +45,9 @@
'degraded']},
'device_count': {'type': 'integer',
'minimum': 0},
'detail': {'type': 'string'}}},
'detail': {'type': 'string'},
'devices': {'type': 'array',
'items': {'$ref': '#/$defs/ResourceDeviceStatus'}}}},
'ResourceYieldResponse': {'type': 'object',
'additionalProperties': False,
'required': ['decision', 'reason'],
Expand Down
20 changes: 20 additions & 0 deletions argus/webapi/artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ def registered_delivery_artifacts(
title = "Delivered results"
targets: list[Any] = []
completion_summaries: list[object] = []
reply_references: list[object] = []
if isinstance(delivery, dict):
title = str(delivery.get("title") or title).strip() or title
raw_targets = delivery.get("targets")
Expand All @@ -190,6 +191,14 @@ def registered_delivery_artifacts(
from ..core.transcript import read_turns

for turn in reversed(read_turns(life_dir)):
if (
turn.get("role") == "argus"
and not turn.get("mission_result")
and not turn.get("delivery")
and turn.get("success") is not False
and not turn.get("live")
):
reply_references.append(turn.get("text"))
if (turn.get("mission_result") is True and turn.get("success") is True
and not turn.get("item_id")):
# A resumed direct task can verify already-written outputs without
Expand Down Expand Up @@ -247,6 +256,17 @@ def registered_delivery_artifacts(
"group_title": title,
})
if resolved_workspace:
from ..life.delivery import referenced_delivery_paths

for path in referenced_delivery_paths(resolved_workspace, reply_references, limit=12):
if path not in seen:
seen.add(path)
results.append({
"path": path,
"why": "File referenced in a saved reply; not an independently reviewed result.",
"source": "reply",
"group_title": "Referenced files",
})
from ..life.delivery import linked_report_paths

for path in linked_report_paths(resolved_workspace, [row["path"] for row in results]):
Expand Down
16 changes: 16 additions & 0 deletions argus/webapi/routes/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ def _resource_status_payload(snapshot: dict[str, Any], *, now: float) -> dict[st
from ...tools.resource_ledger.status_schema_generated import validate_resource_status

probe = snapshot["probe"]
reserved_devices = {
device["identity"]
for record in snapshot["grants"]
for device in record["grant"]["devices"]
}
holders = []
for record in snapshot["grants"]:
owner = record["owner"]
Expand Down Expand Up @@ -72,6 +77,17 @@ def _resource_status_payload(snapshot: dict[str, Any], *, now: float) -> dict[st
"status": accelerator["status"],
"device_count": len(accelerator["devices"]),
"detail": accelerator["detail"],
"devices": [
{
"index": device["index"],
"name": device["name"],
"total_memory_mib": device["total_memory_mib"],
"used_memory_mib": device["used_memory_mib"],
"utilization_percent": device["utilization_percent"],
"reserved": device["identity"] in reserved_devices,
}
for device in accelerator["devices"]
],
}
for accelerator in probe["accelerators"]
],
Expand Down
8 changes: 8 additions & 0 deletions docs/how-argus-speaks.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ every word is doing work. It is a request for accuracy and grace.

## Principles

Default to an ordinary reader, not someone who knows Argus or the field. Lead
with the answer and what it means for that person, then the evidence and limits
that matter. Explain necessary unfamiliar terms in everyday words at first use.
Keep numbers, sources and uncertainty intact. Simple questions need direct
answers, not a fixed multi-section template; professional questions still need
precise terminology and detail. Give a next step only when the person needs to
act. Internal technical records and parsed closing lines remain unchanged.

1. **Say what happened and what it means, in the words of the field.**
"The effect held on the untouched worlds" rather than "the artifact passed
the gate." "The comparison went against the mechanism" rather than "the
Expand Down
28 changes: 28 additions & 0 deletions docs/web-control-responsiveness.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
# Web request cancellation

## Workbench navigation and runtime controls

The main views are Map, Conversation, and Workbench. Workbench modules are
Research timeline, Execution, AI IDE, and Runtime controls, in that order.
Runtime controls replaces the separate operations modal and project overview.
Legacy `view=mission` links open the conversation; removed or invalid module
selections open Runtime controls. Task history and execution capabilities are
unchanged. New work and adjustments belong in the conversation rather than a
second composer inside runtime controls.

Runtime controls reads device telemetry while visible and keeps maintenance,
recovery, and diagnostics collapsed until needed. Opening the page does not
check/apply source updates, restart a daemon, or submit work. Safe pause drains
current work, and maintenance commands retain command revisions and explicit
confirmation. Read-only views cannot execute controls.

Each GPU card displays the host's original device index, reported model,
compute utilization, memory usage, and Argus reservation state. Computing,
reserved, memory occupied, and no activity are distinct observations. Host
telemetry includes other programs; zero utilization is not proof that a device
is exclusively available. Probe failures remain visible rather than becoming
idle cards. The authenticated resource API exposes these normalized facts
without device UUIDs, owner identities, or private project paths.

The attachment button uses the existing Argus mark while retaining its Add files
label and file-picker behavior. Core transitions use brief opacity/transform
feedback, do not replay on every streamed fragment, and honor reduced motion.

The composer stops its current Manager request on the server. Every submission
has a fresh `request_id`; `POST /api/projects/{sid}/message/cancel` targets that
identity. The cancellation POST has its own connection lifetime and a five-second
Expand Down
4 changes: 2 additions & 2 deletions frontend/core/src/eventRender/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ export function renderEvent(event: TypedArgusEvent, context: RenderContext): Ren
case 'ui.argus': {
const body = stringField(event, 'text');
// A reply that is still being worked on has steps before it has words.
const working = Array.isArray(row(event).steps) && (row(event).steps as unknown[]).length > 0;
const working = row(event).live === true || (Array.isArray(row(event).steps) && (row(event).steps as unknown[]).length > 0);
return body.trim() || working
? model('manager', 'role.argus', '▌', body, 'bright', { expandable: context.density === 'full', rule: true })
: hidden();
Expand Down Expand Up @@ -718,7 +718,7 @@ export function renderLine(event: EventMsg, context: RenderContext): RenderedLin
const modelValue = renderEvent(event as TypedArgusEvent, context);
if (modelValue.visibility === 'hidden') return null;
const text = renderText(modelValue);
if (!text && !(event.type === 'ui.argus' && Array.isArray(event.steps) && event.steps.length > 0)) return null;
if (!text && !(event.type === 'ui.argus' && (event.live === true || (Array.isArray(event.steps) && event.steps.length > 0)))) return null;
return {
role: modelValue.role,
labelKey: modelValue.labelKey,
Expand Down
4 changes: 2 additions & 2 deletions frontend/core/src/release.generated.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Generated by argus.release_tools.generate_manifest. Do not edit.
export const RELEASE_ID = "0.1.8+901a92ac03f54664";
export const RELEASE_SOURCE_DIGEST = "901a92ac03f54664634bf33d57067cca393e7039321795e2fdcffc41378aa28a";
export const RELEASE_ID = "0.1.8+057b2aeae2b5e64e";
export const RELEASE_SOURCE_DIGEST = "057b2aeae2b5e64e0118bc9559681345bbc0b5bb4c56420f9f5fa34617a07c67";
10 changes: 10 additions & 0 deletions frontend/core/src/resourceStatus.generated.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
// Generated by argus.release_tools.generate_resource_status. Do not edit.

export interface ResourceDeviceStatus {
readonly "index": string;
readonly "name": string;
readonly "total_memory_mib": number;
readonly "used_memory_mib": number;
readonly "utilization_percent": number;
readonly "reserved": boolean;
}

export interface ResourceAcceleratorStatus {
readonly "kind": string;
readonly "status": "available" | "absent" | "inaccessible" | "degraded";
readonly "device_count": number;
readonly "detail": string;
readonly "devices"?: ReadonlyArray<ResourceDeviceStatus>;
}

export interface ResourceYieldResponse {
Expand Down
44 changes: 22 additions & 22 deletions frontend/tui/bundle/argus.mjs

Large diffs are not rendered by default.

Loading
Loading