ms-tau-sdk 1.2.8.dev13__tar.gz → 1.2.9.dev15__tar.gz
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.
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/CHANGELOG.md +21 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/PKG-INFO +11 -7
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/README.md +10 -6
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/packages/tau-board/src/ms_tau_board/proxy.py +24 -1
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/packages/tau-board/src/ms_tau_board/static/app.js +250 -7
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/packages/tau-board/src/ms_tau_board/static/board.css +7 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/packages/tau-board/src/ms_tau_board/static/index.html +40 -3
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/pyproject.toml +1 -1
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/agent_skills/tau_local_development/SKILL.md +21 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/agent_skills/tau_project_customization/SKILL.md +36 -2
- ms_tau_sdk-1.2.9.dev15/src/ms_tau_sdk/api/inspection.py +122 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/api/models.py +11 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/app.py +2 -1
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/errors.py +15 -0
- ms_tau_sdk-1.2.9.dev15/src/ms_tau_sdk/resources/SYSTEM.md +11 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/runtime/extensions.py +32 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/runtime/manager.py +714 -17
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/runtime/session.py +14 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/settings.py +5 -0
- ms_tau_sdk-1.2.8.dev13/src/ms_tau_sdk/resources/SYSTEM.md +0 -12
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/.gitignore +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/packages/tau-board/src/ms_tau_board/__init__.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/packages/tau-board/src/ms_tau_board/app.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/packages/tau-board/src/ms_tau_board/cli.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/packages/tau-board/src/ms_tau_board/config.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/packages/tau-board/src/ms_tau_board/env_file.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/packages/tau-board/src/ms_tau_board/logs.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/packages/tau-board/src/ms_tau_board/state.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/packages/tau-board/src/ms_tau_board/static/BULMA-LICENSE.txt +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/packages/tau-board/src/ms_tau_board/static/bulma.min.css +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/__init__.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/agent_skills/tau_a2a_runtime_adapter/SKILL.md +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/agent_skills/tau_repository_integration/SKILL.md +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/api/__init__.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/api/a2a.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/api/chat.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/api/dependencies.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/api/health.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/api/sessions.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/application.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/backend/__init__.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/backend/auth.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/backend/client.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/backend/local.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/backend/mcp.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/backend/models.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/backend/routes.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/cli.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/logging.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/protocols/__init__.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/protocols/a2a_message.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/protocols/a2a_roles.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/protocols/assistant_ui.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/protocols/strict_json.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/providers/__init__.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/providers/definitions.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/providers/factory.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/resources/__init__.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/resources/loader.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/resources/prompts/review-code-repository.md +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/runtime/__init__.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/runtime/deployment_health.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/runtime/events.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/runtime/failures.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/runtime/observability.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/runtime/provenance.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/runtime/snapshots.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/runtime/task_context.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/sessions/__init__.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/sessions/storage.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/skills.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/tools/__init__.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/tools/mainsequence_mcp.py +0 -0
- {ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/src/ms_tau_sdk/tools/task_control.py +0 -0
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.9 — 2026-09-25
|
|
4
|
+
|
|
5
|
+
- Added Tau Board's Agent view for readable effective Agent Card inspection, source-grouped tool
|
|
6
|
+
catalog inspection, project extension diagnostics, and bounded registered-entry source viewing.
|
|
7
|
+
- Added an explicit local project-tool workbench with schema-generated inputs, authoritative
|
|
8
|
+
validation, short-lived single-use confirmation, exact loaded-tool execution, streamed bounded
|
|
9
|
+
results, timeout and cancellation. It does not call the model or write conversation/Task history;
|
|
10
|
+
project code still has its normal real side effects.
|
|
11
|
+
- Added creation and completion/status timing to the A2A Task view. Completion uses the standard
|
|
12
|
+
A2A `task.status.timestamp`; creation is joined from Tau's existing local SQLite Task state, so
|
|
13
|
+
the wire contract remains standard.
|
|
14
|
+
|
|
15
|
+
## 1.2.8 — 2026-09-24
|
|
16
|
+
|
|
17
|
+
- Added independent `TAU_EXCLUDE_BASE_TOOLS` and `TAU_EXCLUDE_MAINSEQUENCE_MCP` process settings.
|
|
18
|
+
Deployments can expose only project extension tools plus the two required A2A Task controls.
|
|
19
|
+
The runtime skips MCP connection and resource guidance when excluded, rejects project overrides
|
|
20
|
+
of the Task controls, and checks the effective catalog on load and after extension reload.
|
|
21
|
+
- Documented the settings for managed workflow `env_vars` and local runtimes in ADR 0011, the
|
|
22
|
+
reference guides, and the version-matched `tau-project-customization` skill.
|
|
23
|
+
|
|
3
24
|
## 1.2.7 — 2026-09-21
|
|
4
25
|
|
|
5
26
|
- Bundle the local Tau Board command, Python package, and UI assets in the `ms-tau-sdk` wheel.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: ms-tau-sdk
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.9.dev15
|
|
4
4
|
Summary: Workspace-bound Tau application primitives for Main Sequence projects
|
|
5
5
|
Project-URL: Changelog, https://github.com/mainsequence-sdk/ms-tau-sdk/blob/development/CHANGELOG.md
|
|
6
6
|
Project-URL: Documentation, https://github.com/mainsequence-sdk/ms-tau-sdk/tree/development/docs
|
|
@@ -163,16 +163,20 @@ Tau Board ships in the same SDK wheel. The `tau-board` extra declares its tested
|
|
|
163
163
|
bounds; plain SDK installations never start the board.
|
|
164
164
|
|
|
165
165
|
Open `http://127.0.0.1:8788` to chat, send A2A Messages and Tasks, inspect local SQLite state,
|
|
166
|
-
|
|
166
|
+
inspect the effective Agent Card and tool catalog, validate and explicitly run project extension
|
|
167
|
+
tools, and read logs. The A2A view combines the standard current-status timestamp with Tau's local
|
|
168
|
+
creation timestamp. Tool tests call the exact loaded tool without a model turn or history entry,
|
|
169
|
+
but execute real project code with its normal side effects. The board serves packaged Bulma CSS
|
|
170
|
+
with no frontend build or CDN. It can select
|
|
167
171
|
another loopback Tau endpoint and local state directory in its Connect view. Its Settings tab shows
|
|
168
172
|
the board process's safe environment values and edits named non-secret variables in a local `.env`
|
|
169
173
|
file; Tau or the board must restart before saved startup values take effect.
|
|
170
174
|
|
|
171
175
|
Platform discovery of the unregistered process, internal backend dispatch/caller-delivery hooks,
|
|
172
|
-
push notifications, and `resume_caller` remain unavailable.
|
|
173
|
-
supports Messages and Tasks with polling under authenticated-user semantics
|
|
174
|
-
`127.0.0.1` unless a host was
|
|
175
|
-
|
|
176
|
+
push notifications, and `resume_caller` remain unavailable. When Main Sequence MCP is enabled,
|
|
177
|
+
outbound A2A supports Messages and Tasks with polling under authenticated-user semantics, and MCP
|
|
178
|
+
tools can read or mutate real platform resources. Local mode binds to `127.0.0.1` unless a host was
|
|
179
|
+
explicitly configured.
|
|
176
180
|
|
|
177
181
|
## Workspace-owned Tau behavior
|
|
178
182
|
|
|
@@ -201,7 +205,7 @@ are not bundled into the SDK. Main Sequence transport and protocol behavior rema
|
|
|
201
205
|
- durable Tau sessions, leases, restore, persistence, cancellation, eviction, and shutdown
|
|
202
206
|
- local Tau execution without backend AgentSession pre-creation
|
|
203
207
|
- chat, SSE, A2A, health, and readiness transports
|
|
204
|
-
- Main Sequence MCP and protocol-required task controls
|
|
208
|
+
- optional Main Sequence MCP and always-present protocol-required task controls
|
|
205
209
|
- packaged defaults that participate in Tau's normal workspace configuration
|
|
206
210
|
- explicit, version-matched development skills for repository integration, local debugging,
|
|
207
211
|
project customization, and TAU's A2A host adapter
|
|
@@ -132,16 +132,20 @@ Tau Board ships in the same SDK wheel. The `tau-board` extra declares its tested
|
|
|
132
132
|
bounds; plain SDK installations never start the board.
|
|
133
133
|
|
|
134
134
|
Open `http://127.0.0.1:8788` to chat, send A2A Messages and Tasks, inspect local SQLite state,
|
|
135
|
-
|
|
135
|
+
inspect the effective Agent Card and tool catalog, validate and explicitly run project extension
|
|
136
|
+
tools, and read logs. The A2A view combines the standard current-status timestamp with Tau's local
|
|
137
|
+
creation timestamp. Tool tests call the exact loaded tool without a model turn or history entry,
|
|
138
|
+
but execute real project code with its normal side effects. The board serves packaged Bulma CSS
|
|
139
|
+
with no frontend build or CDN. It can select
|
|
136
140
|
another loopback Tau endpoint and local state directory in its Connect view. Its Settings tab shows
|
|
137
141
|
the board process's safe environment values and edits named non-secret variables in a local `.env`
|
|
138
142
|
file; Tau or the board must restart before saved startup values take effect.
|
|
139
143
|
|
|
140
144
|
Platform discovery of the unregistered process, internal backend dispatch/caller-delivery hooks,
|
|
141
|
-
push notifications, and `resume_caller` remain unavailable.
|
|
142
|
-
supports Messages and Tasks with polling under authenticated-user semantics
|
|
143
|
-
`127.0.0.1` unless a host was
|
|
144
|
-
|
|
145
|
+
push notifications, and `resume_caller` remain unavailable. When Main Sequence MCP is enabled,
|
|
146
|
+
outbound A2A supports Messages and Tasks with polling under authenticated-user semantics, and MCP
|
|
147
|
+
tools can read or mutate real platform resources. Local mode binds to `127.0.0.1` unless a host was
|
|
148
|
+
explicitly configured.
|
|
145
149
|
|
|
146
150
|
## Workspace-owned Tau behavior
|
|
147
151
|
|
|
@@ -170,7 +174,7 @@ are not bundled into the SDK. Main Sequence transport and protocol behavior rema
|
|
|
170
174
|
- durable Tau sessions, leases, restore, persistence, cancellation, eviction, and shutdown
|
|
171
175
|
- local Tau execution without backend AgentSession pre-creation
|
|
172
176
|
- chat, SSE, A2A, health, and readiness transports
|
|
173
|
-
- Main Sequence MCP and protocol-required task controls
|
|
177
|
+
- optional Main Sequence MCP and always-present protocol-required task controls
|
|
174
178
|
- packaged defaults that participate in Tau's normal workspace configuration
|
|
175
179
|
- explicit, version-matched development skills for repository integration, local debugging,
|
|
176
180
|
project customization, and TAU's A2A host adapter
|
{ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/packages/tau-board/src/ms_tau_board/proxy.py
RENAMED
|
@@ -27,6 +27,24 @@ ALLOWED: tuple[tuple[str, re.Pattern[str]], ...] = (
|
|
|
27
27
|
("GET", re.compile(r"/api/a2a/v1/tasks/[A-Za-z0-9._-]+:subscribe")),
|
|
28
28
|
("POST", re.compile(r"/api/a2a/v1/tasks/[A-Za-z0-9._-]+:cancel")),
|
|
29
29
|
("GET", re.compile(r"/api/a2a/v1/extendedAgentCard")),
|
|
30
|
+
(
|
|
31
|
+
"GET",
|
|
32
|
+
re.compile(r"/api/local/v1/sessions/[A-Za-z0-9._-]+/agent-inspection"),
|
|
33
|
+
),
|
|
34
|
+
(
|
|
35
|
+
"GET",
|
|
36
|
+
re.compile(r"/api/local/v1/sessions/[A-Za-z0-9._-]+/extension-sources/[a-f0-9]{24}"),
|
|
37
|
+
),
|
|
38
|
+
(
|
|
39
|
+
"POST",
|
|
40
|
+
re.compile(
|
|
41
|
+
r"/api/local/v1/sessions/[A-Za-z0-9._-]+/tools/[A-Za-z0-9._-]+:(?:validate|test)"
|
|
42
|
+
),
|
|
43
|
+
),
|
|
44
|
+
(
|
|
45
|
+
"POST",
|
|
46
|
+
re.compile(r"/api/local/v1/sessions/[A-Za-z0-9._-]+/tool-tests/[A-Za-z0-9-]+:cancel"),
|
|
47
|
+
),
|
|
30
48
|
)
|
|
31
49
|
|
|
32
50
|
|
|
@@ -82,7 +100,12 @@ async def forward(
|
|
|
82
100
|
raise TauUnavailable("Tau endpoint redirected a board request")
|
|
83
101
|
response_headers = {
|
|
84
102
|
name: upstream.headers[name]
|
|
85
|
-
for name in (
|
|
103
|
+
for name in (
|
|
104
|
+
"x-agent-session-uid",
|
|
105
|
+
"x-tau-tool-test-uid",
|
|
106
|
+
"cache-control",
|
|
107
|
+
"x-vercel-ai-ui-message-stream",
|
|
108
|
+
)
|
|
86
109
|
if name in upstream.headers
|
|
87
110
|
}
|
|
88
111
|
media_type = upstream.headers.get("content-type", "application/json").split(";", 1)[0]
|
{ms_tau_sdk-1.2.8.dev13 → ms_tau_sdk-1.2.9.dev15}/packages/tau-board/src/ms_tau_board/static/app.js
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const $ = (id) => document.getElementById(id);
|
|
2
|
-
const views = ["connect", "chat", "a2a", "tasks", "state", "logs", "settings"];
|
|
2
|
+
const views = ["connect", "agent", "chat", "a2a", "tasks", "state", "logs", "settings"];
|
|
3
3
|
const tables = ["sessions", "entries", "a2a_tasks", "a2a_task_messages", "a2a_task_outputs", "a2a_task_attempts", "a2a_task_events", "snapshots"];
|
|
4
4
|
let config = { profiles: [], selectedProfile: "" };
|
|
5
5
|
let activeView = "connect";
|
|
@@ -20,6 +20,12 @@ let logOffset = 0;
|
|
|
20
20
|
let logRecords = [];
|
|
21
21
|
let logHasMore = false;
|
|
22
22
|
let requestedLogSession = "";
|
|
23
|
+
let agentInspection = null;
|
|
24
|
+
let selectedTool = null;
|
|
25
|
+
let toolConfirmation = "";
|
|
26
|
+
let currentToolTest = "";
|
|
27
|
+
let toolTestAbort = null;
|
|
28
|
+
const a2aTaskState = new Map();
|
|
23
29
|
const catalogs = new Map();
|
|
24
30
|
const desiredSelection = { chat: null, a2a: null };
|
|
25
31
|
|
|
@@ -37,7 +43,11 @@ function notice(message, kind = "is-info") {
|
|
|
37
43
|
}
|
|
38
44
|
function dismissNotice() { $("notice").className = "notification is-hidden"; }
|
|
39
45
|
function errorMessage(data, status) {
|
|
40
|
-
if (data && typeof data === "object")
|
|
46
|
+
if (data && typeof data === "object") {
|
|
47
|
+
const value = data.error || data.message || data.detail;
|
|
48
|
+
if (value && typeof value === "object") return value.message || JSON.stringify(value);
|
|
49
|
+
return value || `HTTP ${status}`;
|
|
50
|
+
}
|
|
41
51
|
return String(data || `HTTP ${status}`);
|
|
42
52
|
}
|
|
43
53
|
async function json(url, options = {}) {
|
|
@@ -62,7 +72,7 @@ function populateSelect(select, values, selected) {
|
|
|
62
72
|
select.value = selected;
|
|
63
73
|
}
|
|
64
74
|
function renderProfiles() {
|
|
65
|
-
for (const id of ["connect-select", "chat-profile", "a2a-profile", "tasks-profile", "log-profile"]) {
|
|
75
|
+
for (const id of ["connect-select", "agent-profile", "chat-profile", "a2a-profile", "tasks-profile", "log-profile"]) {
|
|
66
76
|
const select = $(id);
|
|
67
77
|
const selected = id === "connect-select" ? config.selectedProfile : (select.value || config.selectedProfile);
|
|
68
78
|
clear(select);
|
|
@@ -214,11 +224,191 @@ function showView(view) {
|
|
|
214
224
|
document.querySelector(`[data-nav="${item}"]`).classList.toggle("is-active", item === activeView);
|
|
215
225
|
}
|
|
216
226
|
if (activeView === "a2a") refreshTasks().catch(report);
|
|
227
|
+
if (activeView === "agent") refreshAgentSessions().catch(report);
|
|
217
228
|
if (activeView === "tasks") refreshTaskExplorer().catch(report);
|
|
218
229
|
if (activeView === "state") refreshState().catch(report);
|
|
219
230
|
if (activeView === "logs") refreshLogChoices().then(() => refreshLogs()).catch(report);
|
|
220
231
|
if (activeView === "settings") refreshSettings().catch(report);
|
|
221
232
|
}
|
|
233
|
+
function agentHeaders(extra = {}) { return { "X-Tau-Board-Profile": $("agent-profile").value, ...extra }; }
|
|
234
|
+
function agentSession() { return $("agent-session").value; }
|
|
235
|
+
function invalidateToolConfirmation() {
|
|
236
|
+
toolConfirmation = "";
|
|
237
|
+
$("tool-run").disabled = true;
|
|
238
|
+
clear($("tool-test-status"));
|
|
239
|
+
}
|
|
240
|
+
async function refreshAgentSessions() {
|
|
241
|
+
const previous = agentSession() || $("chat-session").value.trim() || $("a2a-context").value.trim();
|
|
242
|
+
const result = await json("/api/board/sessions", { headers: agentHeaders() });
|
|
243
|
+
const select = $("agent-session"); clear(select);
|
|
244
|
+
select.append(option("", "Select a loaded local session"));
|
|
245
|
+
for (const session of result.sessions || []) select.append(option(session.uid, `${session.uid} · ${session.model || "unknown model"}`));
|
|
246
|
+
select.value = previous;
|
|
247
|
+
if (!select.value && select.options.length === 2) select.selectedIndex = 1;
|
|
248
|
+
if (select.value) await inspectAgent();
|
|
249
|
+
}
|
|
250
|
+
function renderAgentCard(card) {
|
|
251
|
+
const box = $("agent-card"); clear(box);
|
|
252
|
+
if (!card) { box.append(node("p", "No Agent Card was returned.", "help")); $("agent-card-json").textContent = "null"; return; }
|
|
253
|
+
for (const [label, value] of [["Name", card.name], ["Description", card.description], ["Version", card.version], ["URL", card.url]]) detailLine(box, label, value);
|
|
254
|
+
const capabilities = card.capabilities || {};
|
|
255
|
+
detailLine(box, "Capabilities", Object.entries(capabilities).filter(([, value]) => typeof value === "boolean" && value).map(([name]) => name).join(", ") || "None declared");
|
|
256
|
+
detailLine(box, "Protocol extensions", (capabilities.extensions || []).map((item) => item.uri || "unnamed").join(", ") || "None");
|
|
257
|
+
detailLine(box, "Agent Card skills", (card.skills || []).map((item) => item.name || item.id || "unnamed").join(", ") || "None");
|
|
258
|
+
$("agent-card-json").textContent = JSON.stringify(card, null, 2);
|
|
259
|
+
}
|
|
260
|
+
function renderExtensions(items, diagnostics) {
|
|
261
|
+
const box = $("agent-extensions"); clear(box);
|
|
262
|
+
for (const item of items || []) {
|
|
263
|
+
const card = node("div", "", "extension-card");
|
|
264
|
+
card.append(node("strong", item.name), node("span", ` ${item.origin}`, "tag is-light ml-2"));
|
|
265
|
+
card.append(node("p", item.entryPath || "Source is not exposed", "mono"));
|
|
266
|
+
card.append(node("p", `Tools: ${(item.tools || []).join(", ") || "none"}`, "help")); box.append(card);
|
|
267
|
+
}
|
|
268
|
+
for (const item of diagnostics || []) {
|
|
269
|
+
const card = node("div", "", "extension-card has-text-danger");
|
|
270
|
+
card.textContent = `${item.severity} · ${item.name} · ${item.errorType}${item.path ? ` · ${item.path}` : ""}`; box.append(card);
|
|
271
|
+
}
|
|
272
|
+
if (!(items || []).length && !(diagnostics || []).length) box.append(node("p", "No project extensions or diagnostics.", "help"));
|
|
273
|
+
}
|
|
274
|
+
function renderTools(tools) {
|
|
275
|
+
const box = $("agent-tools"); clear(box);
|
|
276
|
+
const labels = { project_extension: "Project extensions", tau_coding: "Tau coding", mainsequence_mcp: "Main Sequence MCP", protocol: "A2A Task controls", user_extension: "User extensions", built_in_extension: "Tau extensions", explicit_extension: "Explicit extensions", unknown_extension: "Other extensions" };
|
|
277
|
+
const groups = new Map();
|
|
278
|
+
for (const tool of tools || []) {
|
|
279
|
+
if (!groups.has(tool.category)) groups.set(tool.category, []);
|
|
280
|
+
groups.get(tool.category).push(tool);
|
|
281
|
+
}
|
|
282
|
+
const order = ["project_extension", "tau_coding", "mainsequence_mcp", "protocol", ...groups.keys()];
|
|
283
|
+
for (const category of [...new Set(order)]) {
|
|
284
|
+
if (!groups.has(category)) continue;
|
|
285
|
+
box.append(node("p", labels[category] || category, "tool-group"));
|
|
286
|
+
for (const tool of groups.get(category)) {
|
|
287
|
+
const button = node("button", "", "button is-light"); button.type = "button";
|
|
288
|
+
button.append(node("strong", tool.label || tool.name), node("span", `\n${tool.name}`, "mono help"));
|
|
289
|
+
button.addEventListener("click", () => selectTool(tool, button)); box.append(button);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (!(tools || []).length) box.append(node("p", "This session has no executable tools.", "help"));
|
|
293
|
+
}
|
|
294
|
+
function defaultFieldValue(schema) {
|
|
295
|
+
if (Object.hasOwn(schema, "default")) return schema.default;
|
|
296
|
+
if (Array.isArray(schema.examples) && schema.examples.length) return schema.examples[0];
|
|
297
|
+
return "";
|
|
298
|
+
}
|
|
299
|
+
function renderToolForm(schema) {
|
|
300
|
+
const form = $("tool-form"); clear(form);
|
|
301
|
+
const required = new Set(schema.required || []);
|
|
302
|
+
for (const [name, field] of Object.entries(schema.properties || {})) {
|
|
303
|
+
const wrapper = node("div", "", "field tool-field");
|
|
304
|
+
wrapper.append(node("label", `${name}${required.has(name) ? " *" : ""}`, "label"));
|
|
305
|
+
let input;
|
|
306
|
+
if (Array.isArray(field.enum)) {
|
|
307
|
+
const control = node("div", "", "select is-fullwidth"); input = node("select");
|
|
308
|
+
if (!required.has(name)) input.append(option("", "Not set"));
|
|
309
|
+
for (const value of field.enum) input.append(option(JSON.stringify(value), String(value)));
|
|
310
|
+
control.append(input); wrapper.append(control); input.dataset.encoding = "json";
|
|
311
|
+
} else if (field.type === "boolean") {
|
|
312
|
+
const control = node("div", "", "select is-fullwidth"); input = node("select");
|
|
313
|
+
if (!required.has(name)) input.append(option("", "Not set"));
|
|
314
|
+
input.append(option("true", "True"), option("false", "False")); control.append(input); wrapper.append(control); input.dataset.encoding = "json";
|
|
315
|
+
} else if (field.type === "object" || field.type === "array") {
|
|
316
|
+
input = node("textarea", "", "textarea mono"); input.rows = 3; input.dataset.encoding = "json"; wrapper.append(input);
|
|
317
|
+
} else {
|
|
318
|
+
input = node("input", "", "input"); input.type = field.type === "number" || field.type === "integer" ? "number" : "text";
|
|
319
|
+
if (field.type === "integer") input.step = "1"; input.dataset.encoding = field.type || "string"; wrapper.append(input);
|
|
320
|
+
}
|
|
321
|
+
input.dataset.toolField = name; input.dataset.required = required.has(name) ? "true" : "false";
|
|
322
|
+
const initial = defaultFieldValue(field);
|
|
323
|
+
if (initial !== "") input.value = input.dataset.encoding === "json" ? JSON.stringify(initial) : String(initial);
|
|
324
|
+
if (field.description) wrapper.append(node("p", field.description, "help"));
|
|
325
|
+
input.addEventListener("input", () => { invalidateToolConfirmation(); try { $("tool-arguments").value = JSON.stringify(formArguments(), null, 2); } catch (_) { /* raw editor remains available */ } });
|
|
326
|
+
form.append(wrapper);
|
|
327
|
+
}
|
|
328
|
+
if (!Object.keys(schema.properties || {}).length) form.append(node("p", "This tool has no declared fields. Use the JSON editor for additional properties.", "help mb-3"));
|
|
329
|
+
try { $("tool-arguments").value = JSON.stringify(formArguments(), null, 2); } catch (_) { $("tool-arguments").value = "{}"; }
|
|
330
|
+
}
|
|
331
|
+
function formArguments() {
|
|
332
|
+
const result = {};
|
|
333
|
+
for (const input of document.querySelectorAll("[data-tool-field]")) {
|
|
334
|
+
if (input.value === "" && input.dataset.required !== "true") continue;
|
|
335
|
+
let value = input.value;
|
|
336
|
+
if (input.dataset.encoding === "json") value = JSON.parse(value || "null");
|
|
337
|
+
else if (input.dataset.encoding === "number") value = Number(value);
|
|
338
|
+
else if (input.dataset.encoding === "integer") value = Number.parseInt(value, 10);
|
|
339
|
+
result[input.dataset.toolField] = value;
|
|
340
|
+
}
|
|
341
|
+
return result;
|
|
342
|
+
}
|
|
343
|
+
function selectTool(tool, button) {
|
|
344
|
+
selectedTool = tool; invalidateToolConfirmation(); currentToolTest = "";
|
|
345
|
+
for (const item of $("agent-tools").querySelectorAll("button")) item.classList.toggle("is-selected", item === button);
|
|
346
|
+
$("tool-title").textContent = tool.label || tool.name;
|
|
347
|
+
$("tool-description").textContent = tool.description || "No description.";
|
|
348
|
+
const meta = $("tool-meta"); clear(meta);
|
|
349
|
+
for (const value of [tool.name, tool.category, tool.executionMode, tool.extension]) if (value) meta.append(node("span", value, "tag is-light"));
|
|
350
|
+
$("tool-schema").textContent = JSON.stringify(tool.parameters, null, 2);
|
|
351
|
+
$("tool-source").disabled = !tool.sourceUid; $("tool-source-output").classList.add("is-hidden");
|
|
352
|
+
renderToolForm(tool.parameters || { type: "object", properties: {} });
|
|
353
|
+
$("tool-validate").disabled = !tool.testable;
|
|
354
|
+
$("tool-confirm").checked = false; $("tool-cancel").disabled = true;
|
|
355
|
+
$("tool-output").textContent = tool.testable ? "Fill the arguments, then validate before running." : (tool.testingReason || "This tool is inspect-only.");
|
|
356
|
+
}
|
|
357
|
+
async function inspectAgent() {
|
|
358
|
+
const session = agentSession();
|
|
359
|
+
if (!session) throw new Error("Select a local session to inspect.");
|
|
360
|
+
agentInspection = await json(`/tau/api/local/v1/sessions/${encodeURIComponent(session)}/agent-inspection`, { headers: agentHeaders() });
|
|
361
|
+
if (!agentInspection.available) {
|
|
362
|
+
clear($("agent-tools")); clear($("agent-card")); clear($("agent-extensions"));
|
|
363
|
+
$("agent-overview").textContent = "Session is not loaded. Send a Chat or A2A message, then inspect again."; return;
|
|
364
|
+
}
|
|
365
|
+
const overview = $("agent-overview"); clear(overview);
|
|
366
|
+
for (const [label, value] of [["Agent", agentInspection.agentUid], ["Session", agentInspection.sessionUid], ["Provider", agentInspection.model?.provider], ["Model", agentInspection.model?.model], ["Catalog", agentInspection.catalogDigest], ["State", agentInspection.busy ? "Busy" : "Idle"]]) detailLine(overview, label, value);
|
|
367
|
+
renderAgentCard(agentInspection.agentCard); renderExtensions(agentInspection.extensions, agentInspection.diagnostics); renderTools(agentInspection.tools);
|
|
368
|
+
}
|
|
369
|
+
async function viewToolSource() {
|
|
370
|
+
if (!selectedTool?.sourceUid) return;
|
|
371
|
+
const result = await json(`/tau/api/local/v1/sessions/${encodeURIComponent(agentSession())}/extension-sources/${selectedTool.sourceUid}`, { headers: agentHeaders() });
|
|
372
|
+
const output = $("tool-source-output"); output.textContent = `${result.path}\n\n${result.content}`; output.classList.remove("is-hidden");
|
|
373
|
+
}
|
|
374
|
+
function rawToolArguments() {
|
|
375
|
+
const value = JSON.parse($("tool-arguments").value || "{}");
|
|
376
|
+
if (!value || Array.isArray(value) || typeof value !== "object") throw new Error("Tool arguments must be a JSON object.");
|
|
377
|
+
return value;
|
|
378
|
+
}
|
|
379
|
+
async function validateTool() {
|
|
380
|
+
if (!selectedTool?.testable) throw new Error("Select a testable project tool.");
|
|
381
|
+
const body = { catalogDigest: agentInspection.catalogDigest, arguments: rawToolArguments() };
|
|
382
|
+
const result = await json(`/tau/api/local/v1/sessions/${encodeURIComponent(agentSession())}/tools/${encodeURIComponent(selectedTool.name)}:validate`, { method: "POST", headers: agentHeaders({ "Content-Type": "application/json" }), body: JSON.stringify(body) });
|
|
383
|
+
toolConfirmation = result.confirmation; $("tool-arguments").value = JSON.stringify(result.arguments, null, 2);
|
|
384
|
+
const status = $("tool-test-status"); clear(status); status.append(node("span", `Validated · confirmation expires in ${result.expiresInSeconds}s`, "tag is-success is-light"));
|
|
385
|
+
$("tool-run").disabled = !$("tool-confirm").checked;
|
|
386
|
+
}
|
|
387
|
+
async function runTool() {
|
|
388
|
+
if (!toolConfirmation || !$("tool-confirm").checked) throw new Error("Validate the arguments and confirm the side-effect warning first.");
|
|
389
|
+
const body = { catalogDigest: agentInspection.catalogDigest, arguments: rawToolArguments(), confirmation: toolConfirmation };
|
|
390
|
+
toolConfirmation = ""; $("tool-run").disabled = true; $("tool-validate").disabled = true; $("tool-output").textContent = "Starting tool…";
|
|
391
|
+
toolTestAbort = new AbortController();
|
|
392
|
+
try {
|
|
393
|
+
const response = await fetch(`/tau/api/local/v1/sessions/${encodeURIComponent(agentSession())}/tools/${encodeURIComponent(selectedTool.name)}:test`, { method: "POST", headers: agentHeaders({ "Content-Type": "application/json" }), body: JSON.stringify(body), signal: toolTestAbort.signal });
|
|
394
|
+
if (!response.ok) throw new Error(errorMessage(await response.json().catch(() => ({})), response.status));
|
|
395
|
+
currentToolTest = response.headers.get("X-Tau-Tool-Test-Uid") || ""; $("tool-cancel").disabled = !currentToolTest;
|
|
396
|
+
await readSSE(response, (event) => {
|
|
397
|
+
if (event.type === "started") $("tool-output").textContent = `Running ${event.toolName}…`;
|
|
398
|
+
if (event.type === "update") $("tool-output").textContent += `\n\nUpdate:\n${JSON.stringify(event.result, null, 2)}`;
|
|
399
|
+
if (event.type === "completed") $("tool-output").textContent = `${event.truncated ? "TRUNCATED\n" : ""}${JSON.stringify(event.result, null, 2)}`;
|
|
400
|
+
if (event.type === "error") $("tool-output").textContent = `${event.errorType || event.error}: ${event.message}`;
|
|
401
|
+
if (event.type === "cancelled") $("tool-output").textContent += "\n\nCancelled.";
|
|
402
|
+
if (event.type === "finished") { const status = $("tool-test-status"); clear(status); status.append(node("span", event.outcome, `tag ${event.outcome === "completed" ? "is-success" : "is-warning"} is-light`)); }
|
|
403
|
+
});
|
|
404
|
+
} finally {
|
|
405
|
+
currentToolTest = ""; toolTestAbort = null; $("tool-cancel").disabled = true; $("tool-validate").disabled = !selectedTool?.testable; $("tool-confirm").checked = false;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
async function cancelTool() {
|
|
409
|
+
if (!currentToolTest) return;
|
|
410
|
+
await json(`/tau/api/local/v1/sessions/${encodeURIComponent(agentSession())}/tool-tests/${encodeURIComponent(currentToolTest)}:cancel`, { method: "POST", headers: agentHeaders({ "Content-Type": "application/json" }), body: "{}" });
|
|
411
|
+
}
|
|
222
412
|
function report(error) { notice(error.message || String(error), "is-danger"); }
|
|
223
413
|
function chatLine(who, type = "agent") {
|
|
224
414
|
const item = node("div", "", `chat-line ${type}`);
|
|
@@ -319,11 +509,37 @@ function taskText(task) {
|
|
|
319
509
|
const parts = (task.artifacts || []).flatMap((artifact) => artifact.parts || []);
|
|
320
510
|
return parts.map((part) => part.text ?? (part.data ? JSON.stringify(part.data, null, 2) : "")).filter(Boolean).join("\n");
|
|
321
511
|
}
|
|
512
|
+
const terminalTaskStates = new Set([
|
|
513
|
+
"TASK_STATE_COMPLETED", "TASK_STATE_FAILED", "TASK_STATE_CANCELED", "TASK_STATE_REJECTED",
|
|
514
|
+
]);
|
|
515
|
+
function taskTiming(task) {
|
|
516
|
+
const local = a2aTaskState.get(task.id) || {};
|
|
517
|
+
const statusTime = task.status?.timestamp || local.status_timestamp || "";
|
|
518
|
+
const state = task.status?.state || "TASK_STATE_UNKNOWN";
|
|
519
|
+
return {
|
|
520
|
+
created: local.created_at || "",
|
|
521
|
+
statusTime,
|
|
522
|
+
terminal: terminalTaskStates.has(state),
|
|
523
|
+
completed: state === "TASK_STATE_COMPLETED",
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
function displayTime(value) {
|
|
527
|
+
if (!value) return "—";
|
|
528
|
+
const parsed = new Date(value);
|
|
529
|
+
return Number.isNaN(parsed.valueOf()) ? value : parsed.toLocaleString();
|
|
530
|
+
}
|
|
531
|
+
function timedCell(value, label = "") {
|
|
532
|
+
const cell = node("td", label ? `${label}: ${displayTime(value)}` : displayTime(value));
|
|
533
|
+
if (value) { cell.classList.add("mono"); cell.title = value; }
|
|
534
|
+
return cell;
|
|
535
|
+
}
|
|
322
536
|
function displayTask(task) {
|
|
323
537
|
if (!task) return;
|
|
324
538
|
$("a2a-task-id").value = task.id || "";
|
|
325
539
|
$("a2a-context").value = task.contextId || "";
|
|
326
|
-
|
|
540
|
+
const timing = taskTiming(task);
|
|
541
|
+
const statusLabel = timing.completed ? "Completed" : (timing.terminal ? "Terminal status" : "Status recorded");
|
|
542
|
+
$("task-output").textContent = `${task.id} · ${task.status?.state || "unknown"}\nCreated: ${displayTime(timing.created)}\n${statusLabel}: ${displayTime(timing.statusTime)}\n\n${taskText(task)}`;
|
|
327
543
|
}
|
|
328
544
|
function handleA2AFrame(frame) {
|
|
329
545
|
const value = frame.result || frame;
|
|
@@ -392,11 +608,26 @@ async function cancelTask(id) {
|
|
|
392
608
|
async function refreshTasks() {
|
|
393
609
|
const contextId = $("a2a-context").value.trim();
|
|
394
610
|
const url = "/tau/api/a2a/v1/tasks" + (contextId ? `?contextId=${encodeURIComponent(contextId)}` : "");
|
|
395
|
-
const
|
|
611
|
+
const headers = tauHeaders("a2a");
|
|
612
|
+
const localUrl = "/api/board/tasks" + (contextId ? `?sessionUid=${encodeURIComponent(contextId)}` : "");
|
|
613
|
+
const [value, localValue] = await Promise.all([
|
|
614
|
+
json(url, { headers }),
|
|
615
|
+
json(localUrl, { headers }),
|
|
616
|
+
]);
|
|
617
|
+
a2aTaskState.clear();
|
|
618
|
+
for (const task of localValue.tasks || []) a2aTaskState.set(task.task_id, task);
|
|
396
619
|
const body = $("task-list"); clear(body);
|
|
397
620
|
for (const task of (value.tasks || []).slice(-100).reverse()) {
|
|
398
621
|
const row = node("tr");
|
|
399
|
-
|
|
622
|
+
const timing = taskTiming(task);
|
|
623
|
+
const statusLabel = timing.completed ? "Completed" : (timing.terminal ? "Terminal" : "Status");
|
|
624
|
+
row.append(
|
|
625
|
+
node("td", task.id, "mono"),
|
|
626
|
+
node("td", task.contextId || "", "mono"),
|
|
627
|
+
node("td", task.status?.state || ""),
|
|
628
|
+
timedCell(timing.created),
|
|
629
|
+
timedCell(timing.statusTime, statusLabel),
|
|
630
|
+
);
|
|
400
631
|
const actions = node("td");
|
|
401
632
|
for (const [label, action] of [["Open", () => getTask(task.id)], ["Inspect", () => { $("tasks-profile").value = $("a2a-profile").value; selectedTaskId = task.id; showView("tasks"); }], ["Follow", () => subscribeTask(task.id)], ["Cancel", () => cancelTask(task.id)], ["Continue", () => {
|
|
402
633
|
$("a2a-kind").value = "continue"; $("a2a-task-id").value = task.id; $("a2a-context").value = task.contextId || ""; $("a2a-input").focus();
|
|
@@ -407,7 +638,10 @@ async function refreshTasks() {
|
|
|
407
638
|
}
|
|
408
639
|
row.append(actions); body.append(row);
|
|
409
640
|
}
|
|
410
|
-
if (!(value.tasks || []).length) { const row = node("tr"); const cell = node("td", "No Tasks in this context yet."); cell.colSpan =
|
|
641
|
+
if (!(value.tasks || []).length) { const row = node("tr"); const cell = node("td", "No Tasks in this context yet."); cell.colSpan = 6; row.append(cell); body.append(row); }
|
|
642
|
+
const currentId = $("a2a-task-id").value.trim();
|
|
643
|
+
const current = (value.tasks || []).find((task) => task.id === currentId);
|
|
644
|
+
if (current) displayTask(current);
|
|
411
645
|
}
|
|
412
646
|
async function refreshState() {
|
|
413
647
|
const result = await json("/api/board/state");
|
|
@@ -674,6 +908,15 @@ async function start() {
|
|
|
674
908
|
bind("save-profile", "click", saveProfile);
|
|
675
909
|
bind("delete-profile", "click", deleteProfile);
|
|
676
910
|
bind("check-connection", "click", checkConnection);
|
|
911
|
+
bind("agent-profile", "change", refreshAgentSessions);
|
|
912
|
+
bind("agent-session", "change", inspectAgent);
|
|
913
|
+
bind("agent-refresh", "click", inspectAgent);
|
|
914
|
+
bind("tool-source", "click", viewToolSource);
|
|
915
|
+
bind("tool-validate", "click", validateTool);
|
|
916
|
+
bind("tool-run", "click", runTool);
|
|
917
|
+
bind("tool-cancel", "click", cancelTool);
|
|
918
|
+
bind("tool-confirm", "change", () => { $("tool-run").disabled = !toolConfirmation || !$("tool-confirm").checked; });
|
|
919
|
+
$("tool-arguments").addEventListener("input", invalidateToolConfirmation);
|
|
677
920
|
for (const kind of ["chat", "a2a"]) {
|
|
678
921
|
bind(`${kind}-profile`, "change", () => loadCatalog(kind));
|
|
679
922
|
for (const field of ["provider", "model", "thinking"]) bind(`${kind}-${field}`, "change", () => selectionChanged(kind, field));
|
|
@@ -32,6 +32,13 @@ td { max-width: 24rem; overflow-wrap: anywhere; font-size: .82rem; }
|
|
|
32
32
|
.task-picker { max-height: 65vh; overflow: auto; }
|
|
33
33
|
.task-picker button { display: block; width: 100%; text-align: left; white-space: normal; height: auto; margin: .35rem 0; overflow-wrap: anywhere; }
|
|
34
34
|
.task-picker button.is-selected { border-color: var(--bulma-primary); background: var(--bulma-scheme-main-ter); color: var(--bulma-text); font-weight: 700; }
|
|
35
|
+
.tool-picker { max-height: 72vh; overflow: auto; }
|
|
36
|
+
.tool-group { margin: 1rem 0 .4rem; color: var(--bulma-text-weak); font-size: .7rem; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; }
|
|
37
|
+
.tool-picker button { display: block; width: 100%; height: auto; margin-bottom: .4rem; padding: .65rem; text-align: left; white-space: normal; overflow-wrap: anywhere; }
|
|
38
|
+
.tool-picker button.is-selected { border-color: var(--bulma-primary); background: var(--bulma-primary-soft); }
|
|
39
|
+
.source-panel { max-height: 30rem; overflow: auto; margin-top: .75rem; padding: .75rem; border: 1px solid var(--bulma-border); border-radius: .4rem; background: var(--bulma-scheme-main-bis); white-space: pre-wrap; overflow-wrap: anywhere; font-size: .78rem; }
|
|
40
|
+
.tool-field { margin-bottom: .8rem; }
|
|
41
|
+
.extension-card { border-bottom: 1px solid var(--bulma-border-weak); padding: .55rem 0; font-size: .82rem; overflow-wrap: anywhere; }
|
|
35
42
|
#tasks-detail { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 1rem; }
|
|
36
43
|
.settings-table td { vertical-align: middle; }
|
|
37
44
|
.settings-table td:first-child { min-width: 15rem; }
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
6
|
<title>Tau Board</title>
|
|
7
7
|
<link rel="stylesheet" href="/assets/bulma.min.css">
|
|
8
|
-
<link rel="stylesheet" href="/assets/board.css?v=
|
|
9
|
-
<script type="module" src="/assets/app.js?v=
|
|
8
|
+
<link rel="stylesheet" href="/assets/board.css?v=3">
|
|
9
|
+
<script type="module" src="/assets/app.js?v=3"></script>
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<header class="board-header">
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
<nav class="tabs is-boxed" aria-label="Board views">
|
|
23
23
|
<ul>
|
|
24
24
|
<li class="is-active" data-nav="connect"><a href="#connect">Connect</a></li>
|
|
25
|
+
<li data-nav="agent"><a href="#agent">Agent</a></li>
|
|
25
26
|
<li data-nav="chat"><a href="#chat">Chat</a></li>
|
|
26
27
|
<li data-nav="a2a"><a href="#a2a">A2A</a></li>
|
|
27
28
|
<li data-nav="tasks"><a href="#tasks">Tasks</a></li>
|
|
@@ -59,6 +60,42 @@
|
|
|
59
60
|
</div>
|
|
60
61
|
</section>
|
|
61
62
|
|
|
63
|
+
<section id="view-agent" class="board-view is-hidden">
|
|
64
|
+
<div class="columns is-variable is-4">
|
|
65
|
+
<div class="column is-one-quarter"><div class="box">
|
|
66
|
+
<h2 class="title is-5">Loaded agent</h2>
|
|
67
|
+
<div class="field"><label class="label" for="agent-profile">Endpoint profile</label><div class="select is-fullwidth"><select id="agent-profile"></select></div></div>
|
|
68
|
+
<div class="field"><label class="label" for="agent-session">Local session</label><div class="select is-fullwidth"><select id="agent-session"><option value="">No session selected</option></select></div><p class="help">Inspection never loads a session. Start or resume it through Chat or A2A first.</p></div>
|
|
69
|
+
<button class="button is-primary is-fullwidth" id="agent-refresh">Inspect agent</button>
|
|
70
|
+
<div id="agent-overview" class="detail-list mt-4">Select an already loaded session.</div>
|
|
71
|
+
<details class="mt-4"><summary class="has-text-weight-semibold">Effective Agent Card</summary><div id="agent-card" class="detail-list mt-3"></div><pre id="agent-card-json" class="source-panel"></pre></details>
|
|
72
|
+
<details class="mt-4"><summary class="has-text-weight-semibold">Extensions and diagnostics</summary><div id="agent-extensions" class="mt-3"></div></details>
|
|
73
|
+
</div></div>
|
|
74
|
+
<div class="column is-one-quarter"><div class="box">
|
|
75
|
+
<h2 class="title is-5">Effective tools</h2>
|
|
76
|
+
<p class="help mb-3">The exact catalog exposed to the selected session, grouped by runtime ownership.</p>
|
|
77
|
+
<div id="agent-tools" class="tool-picker"></div>
|
|
78
|
+
</div></div>
|
|
79
|
+
<div class="column"><div class="box">
|
|
80
|
+
<h2 id="tool-title" class="title is-5">Tool details</h2>
|
|
81
|
+
<div id="tool-meta" class="tags"></div>
|
|
82
|
+
<p id="tool-description" class="mb-4">Select a tool to inspect its contract.</p>
|
|
83
|
+
<details open><summary class="has-text-weight-semibold">Argument schema</summary><pre id="tool-schema" class="source-panel"></pre></details>
|
|
84
|
+
<div class="buttons mt-3"><button class="button is-small" id="tool-source" disabled>View project source</button></div>
|
|
85
|
+
<pre id="tool-source-output" class="source-panel is-hidden"></pre>
|
|
86
|
+
<hr>
|
|
87
|
+
<h3 class="title is-6">Project tool workbench</h3>
|
|
88
|
+
<div class="notification is-warning is-light">This invokes real project Python code with Tau's filesystem, network, environment, and credential access. It is not a sandbox or rollback.</div>
|
|
89
|
+
<div id="tool-form"></div>
|
|
90
|
+
<div class="field"><label class="label" for="tool-arguments">Canonical JSON arguments</label><textarea class="textarea mono" id="tool-arguments" rows="8" spellcheck="false">{}</textarea></div>
|
|
91
|
+
<div class="buttons"><button class="button" id="tool-validate" disabled>Validate</button><button class="button is-danger" id="tool-run" disabled>Run tool</button><button class="button is-warning is-light" id="tool-cancel" disabled>Cancel</button></div>
|
|
92
|
+
<label class="checkbox mb-4"><input type="checkbox" id="tool-confirm"> I understand this executes real code and may cause side effects.</label>
|
|
93
|
+
<div id="tool-test-status" class="tags"></div>
|
|
94
|
+
<pre id="tool-output" class="output-panel">No tool test has run.</pre>
|
|
95
|
+
</div></div>
|
|
96
|
+
</div>
|
|
97
|
+
</section>
|
|
98
|
+
|
|
62
99
|
<section id="view-chat" class="board-view is-hidden">
|
|
63
100
|
<div class="columns is-variable is-5">
|
|
64
101
|
<div class="column is-one-third"><div class="box">
|
|
@@ -93,7 +130,7 @@
|
|
|
93
130
|
</div></div><div class="column"><div class="box">
|
|
94
131
|
<div class="level"><div class="level-left"><h2 class="title is-5">Tasks</h2></div><div class="level-right"><button class="button is-small" id="refresh-tasks">Refresh</button></div></div>
|
|
95
132
|
<div id="task-output" class="output-panel" aria-live="polite">Choose an action to begin.</div>
|
|
96
|
-
<div class="table-container"><table class="table is-fullwidth is-striped is-hoverable"><thead><tr><th>Task</th><th>Context</th><th>Status</th><th></th></tr></thead><tbody id="task-list"></tbody></table></div>
|
|
133
|
+
<div class="table-container"><table class="table is-fullwidth is-striped is-hoverable"><thead><tr><th>Task</th><th>Context</th><th>Status</th><th>Created</th><th>Completed / status time</th><th></th></tr></thead><tbody id="task-list"></tbody></table></div>
|
|
97
134
|
</div></div></div>
|
|
98
135
|
</section>
|
|
99
136
|
|
|
@@ -102,6 +102,27 @@ identity:
|
|
|
102
102
|
These are the only A2A-adjacent capability boundaries; public local Message and Task requests must not return
|
|
103
103
|
`local_mode_capability_unsupported`.
|
|
104
104
|
|
|
105
|
+
Each standard A2A Task carries the time its current state was recorded in
|
|
106
|
+
`task.status.timestamp`. For `TASK_STATE_COMPLETED`, that is the completion time. The A2A Task
|
|
107
|
+
object has no standard top-level creation timestamp; Tau persists `created_at` in local SQLite,
|
|
108
|
+
and Tau Board joins that local row when it displays the A2A Task list. Do not invent extra A2A
|
|
109
|
+
wire fields for Board presentation.
|
|
110
|
+
|
|
111
|
+
## Inspect and test with Tau Board
|
|
112
|
+
|
|
113
|
+
Install `ms-tau-sdk[tau-board]`, run `tau-board` as a separate process, and connect it to the
|
|
114
|
+
loopback local-mode Tau endpoint. The Agent tab requires an already loaded session: first send a
|
|
115
|
+
Chat or A2A request, then select that session. It shows the effective Agent Card, loaded tools by
|
|
116
|
+
source, project extension diagnostics, and registered project extension entry source.
|
|
117
|
+
|
|
118
|
+
Only project-extension tools with an object JSON Schema are runnable in the workbench. Select the
|
|
119
|
+
tool, fill its generated form or raw JSON, validate the exact canonical arguments, acknowledge
|
|
120
|
+
the side-effect warning, then run it. Validation never calls the tool. Run invokes the exact
|
|
121
|
+
loaded tool without a model call and without adding chat entries, A2A Tasks, or artifacts. The
|
|
122
|
+
tool still has the Tau process's real filesystem, network, environment, and credential access;
|
|
123
|
+
there is no automatic rollback. A busy session, stale catalog, expired confirmation, non-project
|
|
124
|
+
tool, oversized output, timeout, or cancellation must fail explicitly.
|
|
125
|
+
|
|
105
126
|
## Outbound A2A through Main Sequence MCP
|
|
106
127
|
|
|
107
128
|
Keep the projected `a2a.send_message` tool available. A local agent may send a Message or create a
|