@openviking/openclaw-plugin 2026.8.11 → 2026.8.13-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.
package/client.ts CHANGED
@@ -378,13 +378,17 @@ export class OpenVikingClient {
378
378
  const payload = (await response.json().catch(() => ({}))) as {
379
379
  status?: string;
380
380
  result?: T;
381
- error?: { code?: string; message?: string };
381
+ error?: { code?: string; message?: string; trace_id?: string };
382
382
  };
383
383
 
384
384
  if (!response.ok || payload.status === "error") {
385
385
  const code = payload.error?.code ? ` [${payload.error.code}]` : "";
386
386
  const message = payload.error?.message ?? `HTTP ${response.status}`;
387
- throw new Error(`OpenViking request failed${code}: ${message}`);
387
+ const traceId = payload.error?.trace_id;
388
+ throw new Error(
389
+ `OpenViking request failed${code}: ${message}` +
390
+ (traceId ? ` (trace_id=${traceId})` : ""),
391
+ );
388
392
  }
389
393
 
390
394
  return (payload.result ?? payload) as T;
package/config.ts CHANGED
@@ -190,9 +190,6 @@ export const OPENVIKING_TOOL_GROUPS: Record<string, readonly OpenVikingToolName[
190
190
  default: OPENVIKING_DEFAULT_ENABLED_TOOL_NAMES,
191
191
  memory: ["memory_recall", "memory_store", "memory_forget"],
192
192
  resource_query: ["ov_search", "ov_read", "ov_multi_read", "ov_list"],
193
- // Migration alias for configurations that previously selected the removed
194
- // search_experience/read_experience tools.
195
- experience: ["ov_search", "ov_read"],
196
193
  import: ["add_resource", "add_skill"],
197
194
  recall_trace: ["ov_recall_trace"],
198
195
  archive: ["ov_archive_search", "ov_archive_expand"],
@@ -951,7 +948,7 @@ export const memoryOpenVikingConfigSchema = {
951
948
  enabledTools: {
952
949
  label: "Enabled Tools",
953
950
  placeholder: "default",
954
- help: "Agent-visible tool allowlist. Accepts tool names or groups: default, all, memory, resource_query, experience (legacy alias), import, recall_trace, archive, tool_result. add_resource also requires enableAddResourceTool=true.",
951
+ help: "Agent-visible tool allowlist. Accepts tool names or groups: default, all, memory, resource_query, import, recall_trace, archive, tool_result. add_resource also requires enableAddResourceTool=true.",
955
952
  advanced: true,
956
953
  },
957
954
  disabledTools: {
package/dist/client.js CHANGED
@@ -150,7 +150,9 @@ export class OpenVikingClient {
150
150
  if (!response.ok || payload.status === "error") {
151
151
  const code = payload.error?.code ? ` [${payload.error.code}]` : "";
152
152
  const message = payload.error?.message ?? `HTTP ${response.status}`;
153
- throw new Error(`OpenViking request failed${code}: ${message}`);
153
+ const traceId = payload.error?.trace_id;
154
+ throw new Error(`OpenViking request failed${code}: ${message}` +
155
+ (traceId ? ` (trace_id=${traceId})` : ""));
154
156
  }
155
157
  return (payload.result ?? payload);
156
158
  }
package/dist/config.js CHANGED
@@ -54,9 +54,6 @@ export const OPENVIKING_TOOL_GROUPS = {
54
54
  default: OPENVIKING_DEFAULT_ENABLED_TOOL_NAMES,
55
55
  memory: ["memory_recall", "memory_store", "memory_forget"],
56
56
  resource_query: ["ov_search", "ov_read", "ov_multi_read", "ov_list"],
57
- // Migration alias for configurations that previously selected the removed
58
- // search_experience/read_experience tools.
59
- experience: ["ov_search", "ov_read"],
60
57
  import: ["add_resource", "add_skill"],
61
58
  recall_trace: ["ov_recall_trace"],
62
59
  archive: ["ov_archive_search", "ov_archive_expand"],
@@ -653,7 +650,7 @@ export const memoryOpenVikingConfigSchema = {
653
650
  enabledTools: {
654
651
  label: "Enabled Tools",
655
652
  placeholder: "default",
656
- help: "Agent-visible tool allowlist. Accepts tool names or groups: default, all, memory, resource_query, experience (legacy alias), import, recall_trace, archive, tool_result. add_resource also requires enableAddResourceTool=true.",
653
+ help: "Agent-visible tool allowlist. Accepts tool names or groups: default, all, memory, resource_query, import, recall_trace, archive, tool_result. add_resource also requires enableAddResourceTool=true.",
657
654
  advanced: true,
658
655
  },
659
656
  disabledTools: {
@@ -55,27 +55,41 @@ export function registerOpenVikingMemoryTools(deps) {
55
55
  });
56
56
  const memoriesCount = totalCommitMemories(commitResult);
57
57
  if (commitResult.status === "failed") {
58
- deps.logger.warn(`openviking: memory_store commit failed (sessionId=${sessionId}): ${commitResult.error ?? "unknown"}`);
58
+ deps.logger.warn(`openviking: memory_store commit failed (sessionId=${sessionId}): ` +
59
+ `${commitResult.error ?? "unknown"}, trace_id=${commitResult.trace_id ?? "none"}`);
59
60
  return {
60
- content: [{ type: "text", text: `Memory extraction failed for session ${sessionId}: ${commitResult.error ?? "unknown"}` }],
61
+ content: [{
62
+ type: "text",
63
+ text: `Memory extraction failed for session ${sessionId}: ${commitResult.error ?? "unknown"}` +
64
+ (commitResult.trace_id ? ` (trace_id=${commitResult.trace_id})` : ""),
65
+ }],
61
66
  details: {
62
67
  action: "failed",
63
68
  sessionId,
64
69
  status: "failed",
65
70
  error: commitResult.error,
71
+ traceId: commitResult.trace_id,
66
72
  usedTempSession,
67
73
  },
68
74
  };
69
75
  }
70
76
  if (commitResult.status === "timeout") {
71
- deps.logger.warn(`openviking: memory_store commit timed out (sessionId=${sessionId}), task_id=${commitResult.task_id ?? "none"}. Memories may still be extracting in background.`);
77
+ deps.logger.warn(`openviking: memory_store commit timed out (sessionId=${sessionId}), ` +
78
+ `task_id=${commitResult.task_id ?? "none"}, trace_id=${commitResult.trace_id ?? "none"}. ` +
79
+ "Memories may still be extracting in background.");
72
80
  return {
73
- content: [{ type: "text", text: `Memory extraction timed out for session ${sessionId}. It may still complete in the background (task_id=${commitResult.task_id ?? "none"}).` }],
81
+ content: [{
82
+ type: "text",
83
+ text: `Memory extraction timed out for session ${sessionId}. ` +
84
+ `It may still complete in the background (task_id=${commitResult.task_id ?? "none"}` +
85
+ `${commitResult.trace_id ? `, trace_id=${commitResult.trace_id}` : ""}).`,
86
+ }],
74
87
  details: {
75
88
  action: "timeout",
76
89
  sessionId,
77
90
  status: "timeout",
78
91
  taskId: commitResult.task_id,
92
+ traceId: commitResult.trace_id,
79
93
  usedTempSession,
80
94
  },
81
95
  };
@@ -85,13 +99,15 @@ export function registerOpenVikingMemoryTools(deps) {
85
99
  "Check OpenViking server logs for embedding/extract errors (e.g. 401 API key, or extraction pipeline).");
86
100
  }
87
101
  else {
88
- deps.logger.info?.(`openviking: memory_store committed, memories=${memoriesCount}`);
102
+ deps.logger.info?.(`openviking: memory_store committed, memories=${memoriesCount}, ` +
103
+ `trace_id=${commitResult.trace_id ?? "none"}`);
89
104
  }
90
105
  return {
91
106
  content: [
92
107
  {
93
108
  type: "text",
94
- text: `Stored in OpenViking session ${sessionId} and committed ${memoriesCount} memories.`,
109
+ text: `Stored in OpenViking session ${sessionId} and committed ${memoriesCount} memories.` +
110
+ (commitResult.trace_id ? ` (trace_id=${commitResult.trace_id})` : ""),
95
111
  },
96
112
  ],
97
113
  details: {
@@ -100,6 +116,7 @@ export function registerOpenVikingMemoryTools(deps) {
100
116
  memoriesCount,
101
117
  status: commitResult.status,
102
118
  archived: commitResult.archived ?? false,
119
+ traceId: commitResult.trace_id,
103
120
  usedTempSession,
104
121
  },
105
122
  };
@@ -160,11 +160,13 @@ export async function commitOpenVikingSession({ sessionId, sessionKey, getClient
160
160
  });
161
161
  const memCount = totalExtractedMemories(commitResult.memories_extracted);
162
162
  if (commitResult.status === "failed") {
163
- logger.warn?.(`openviking: commit Phase 2 failed for session=${sessionId}: ${commitResult.error ?? "unknown"}`);
163
+ logger.warn?.(`openviking: commit Phase 2 failed for session=${sessionId}: ${commitResult.error ?? "unknown"}, ` +
164
+ `trace_id=${commitResult.trace_id ?? "none"}`);
164
165
  return false;
165
166
  }
166
167
  if (commitResult.status === "timeout") {
167
- logger.warn?.(`openviking: commit Phase 2 timed out for session=${sessionId}, task_id=${commitResult.task_id ?? "none"}`);
168
+ logger.warn?.(`openviking: commit Phase 2 timed out for session=${sessionId}, ` +
169
+ `task_id=${commitResult.task_id ?? "none"}, trace_id=${commitResult.trace_id ?? "none"}`);
168
170
  return false;
169
171
  }
170
172
  logger.info(`openviking: committed OV session=${sessionId} ovId=${ovId}, archived=${commitResult.archived ?? false}, memories=${memCount}, task_id=${commitResult.task_id ?? "none"}, trace_id=${commitResult.trace_id ?? "none"}`);
@@ -722,7 +724,8 @@ export async function compactOpenVikingSession({ sessionId, sessionKey, tokenBud
722
724
  });
723
725
  const memCount = totalExtractedMemories(commitResult.memories_extracted);
724
726
  if (commitResult.status === "failed") {
725
- logger.warn?.(`openviking: compact commit Phase 2 failed for session=${ovSessionId}: ${commitResult.error ?? "unknown"}`);
727
+ logger.warn?.(`openviking: compact commit Phase 2 failed for session=${ovSessionId}: ` +
728
+ `${commitResult.error ?? "unknown"}, trace_id=${commitResult.trace_id ?? "none"}`);
726
729
  diag("compact_result", ovSessionId, {
727
730
  ok: false,
728
731
  compacted: false,
@@ -735,7 +738,8 @@ export async function compactOpenVikingSession({ sessionId, sessionKey, tokenBud
735
738
  return compactFailureResult("commit_failed", tokensBefore, { commit: commitResult });
736
739
  }
737
740
  if (commitResult.status === "timeout") {
738
- logger.warn?.(`openviking: compact commit Phase 2 timed out for session=${ovSessionId}, task_id=${commitResult.task_id ?? "none"}`);
741
+ logger.warn?.(`openviking: compact commit Phase 2 timed out for session=${ovSessionId}, ` +
742
+ `task_id=${commitResult.task_id ?? "none"}, trace_id=${commitResult.trace_id ?? "none"}`);
739
743
  diag("compact_result", ovSessionId, {
740
744
  ok: false,
741
745
  compacted: false,
@@ -41,6 +41,7 @@
41
41
  ".gitignore",
42
42
  "skills/install-openviking-memory/SKILL.md",
43
43
  "skills/openviking-context-database/SKILL.md",
44
+ "skills/ov-experience-memory/SKILL.md",
44
45
  "INSTALL-AGENT.md"
45
46
  ]
46
47
  },
@@ -50,7 +50,8 @@
50
50
  },
51
51
  "skills": [
52
52
  "./skills/install-openviking-memory",
53
- "./skills/openviking-context-database"
53
+ "./skills/openviking-context-database",
54
+ "./skills/ov-experience-memory"
54
55
  ],
55
56
  "setup": {
56
57
  "providers": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openviking/openclaw-plugin",
3
- "version": "2026.8.11",
3
+ "version": "2026.8.13-1",
4
4
  "displayName": "OpenViking",
5
5
  "description": "OpenClaw context-engine plugin — OpenViking AI memory, long-term memory, knowledge base, semantic search, RAG, context engine. 长期记忆 · 知识库 · 语义检索 · 上下文引擎",
6
6
  "type": "module",
@@ -132,30 +132,44 @@ export function registerOpenVikingMemoryTools(deps: OpenVikingMemoryToolsDeps):
132
132
  const memoriesCount = totalCommitMemories(commitResult);
133
133
  if (commitResult.status === "failed") {
134
134
  deps.logger.warn(
135
- `openviking: memory_store commit failed (sessionId=${sessionId}): ${commitResult.error ?? "unknown"}`,
135
+ `openviking: memory_store commit failed (sessionId=${sessionId}): ` +
136
+ `${commitResult.error ?? "unknown"}, trace_id=${commitResult.trace_id ?? "none"}`,
136
137
  );
137
138
  return {
138
- content: [{ type: "text", text: `Memory extraction failed for session ${sessionId}: ${commitResult.error ?? "unknown"}` }],
139
+ content: [{
140
+ type: "text",
141
+ text: `Memory extraction failed for session ${sessionId}: ${commitResult.error ?? "unknown"}` +
142
+ (commitResult.trace_id ? ` (trace_id=${commitResult.trace_id})` : ""),
143
+ }],
139
144
  details: {
140
145
  action: "failed",
141
146
  sessionId,
142
147
  status: "failed",
143
148
  error: commitResult.error,
149
+ traceId: commitResult.trace_id,
144
150
  usedTempSession,
145
151
  },
146
152
  };
147
153
  }
148
154
  if (commitResult.status === "timeout") {
149
155
  deps.logger.warn(
150
- `openviking: memory_store commit timed out (sessionId=${sessionId}), task_id=${commitResult.task_id ?? "none"}. Memories may still be extracting in background.`,
156
+ `openviking: memory_store commit timed out (sessionId=${sessionId}), ` +
157
+ `task_id=${commitResult.task_id ?? "none"}, trace_id=${commitResult.trace_id ?? "none"}. ` +
158
+ "Memories may still be extracting in background.",
151
159
  );
152
160
  return {
153
- content: [{ type: "text", text: `Memory extraction timed out for session ${sessionId}. It may still complete in the background (task_id=${commitResult.task_id ?? "none"}).` }],
161
+ content: [{
162
+ type: "text",
163
+ text: `Memory extraction timed out for session ${sessionId}. ` +
164
+ `It may still complete in the background (task_id=${commitResult.task_id ?? "none"}` +
165
+ `${commitResult.trace_id ? `, trace_id=${commitResult.trace_id}` : ""}).`,
166
+ }],
154
167
  details: {
155
168
  action: "timeout",
156
169
  sessionId,
157
170
  status: "timeout",
158
171
  taskId: commitResult.task_id,
172
+ traceId: commitResult.trace_id,
159
173
  usedTempSession,
160
174
  },
161
175
  };
@@ -166,13 +180,17 @@ export function registerOpenVikingMemoryTools(deps: OpenVikingMemoryToolsDeps):
166
180
  "Check OpenViking server logs for embedding/extract errors (e.g. 401 API key, or extraction pipeline).",
167
181
  );
168
182
  } else {
169
- deps.logger.info?.(`openviking: memory_store committed, memories=${memoriesCount}`);
183
+ deps.logger.info?.(
184
+ `openviking: memory_store committed, memories=${memoriesCount}, ` +
185
+ `trace_id=${commitResult.trace_id ?? "none"}`,
186
+ );
170
187
  }
171
188
  return {
172
189
  content: [
173
190
  {
174
191
  type: "text",
175
- text: `Stored in OpenViking session ${sessionId} and committed ${memoriesCount} memories.`,
192
+ text: `Stored in OpenViking session ${sessionId} and committed ${memoriesCount} memories.` +
193
+ (commitResult.trace_id ? ` (trace_id=${commitResult.trace_id})` : ""),
176
194
  },
177
195
  ],
178
196
  details: {
@@ -181,6 +199,7 @@ export function registerOpenVikingMemoryTools(deps: OpenVikingMemoryToolsDeps):
181
199
  memoriesCount,
182
200
  status: commitResult.status,
183
201
  archived: commitResult.archived ?? false,
202
+ traceId: commitResult.trace_id,
184
203
  usedTempSession,
185
204
  },
186
205
  };
@@ -368,11 +368,17 @@ export async function commitOpenVikingSession({
368
368
  });
369
369
  const memCount = totalExtractedMemories(commitResult.memories_extracted);
370
370
  if (commitResult.status === "failed") {
371
- logger.warn?.(`openviking: commit Phase 2 failed for session=${sessionId}: ${commitResult.error ?? "unknown"}`);
371
+ logger.warn?.(
372
+ `openviking: commit Phase 2 failed for session=${sessionId}: ${commitResult.error ?? "unknown"}, ` +
373
+ `trace_id=${commitResult.trace_id ?? "none"}`,
374
+ );
372
375
  return false;
373
376
  }
374
377
  if (commitResult.status === "timeout") {
375
- logger.warn?.(`openviking: commit Phase 2 timed out for session=${sessionId}, task_id=${commitResult.task_id ?? "none"}`);
378
+ logger.warn?.(
379
+ `openviking: commit Phase 2 timed out for session=${sessionId}, ` +
380
+ `task_id=${commitResult.task_id ?? "none"}, trace_id=${commitResult.trace_id ?? "none"}`,
381
+ );
376
382
  return false;
377
383
  }
378
384
  logger.info(
@@ -1069,7 +1075,8 @@ export async function compactOpenVikingSession({
1069
1075
 
1070
1076
  if (commitResult.status === "failed") {
1071
1077
  logger.warn?.(
1072
- `openviking: compact commit Phase 2 failed for session=${ovSessionId}: ${commitResult.error ?? "unknown"}`,
1078
+ `openviking: compact commit Phase 2 failed for session=${ovSessionId}: ` +
1079
+ `${commitResult.error ?? "unknown"}, trace_id=${commitResult.trace_id ?? "none"}`,
1073
1080
  );
1074
1081
  diag("compact_result", ovSessionId, {
1075
1082
  ok: false,
@@ -1085,7 +1092,8 @@ export async function compactOpenVikingSession({
1085
1092
 
1086
1093
  if (commitResult.status === "timeout") {
1087
1094
  logger.warn?.(
1088
- `openviking: compact commit Phase 2 timed out for session=${ovSessionId}, task_id=${commitResult.task_id ?? "none"}`,
1095
+ `openviking: compact commit Phase 2 timed out for session=${ovSessionId}, ` +
1096
+ `task_id=${commitResult.task_id ?? "none"}, trace_id=${commitResult.trace_id ?? "none"}`,
1089
1097
  );
1090
1098
  diag("compact_result", ovSessionId, {
1091
1099
  ok: false,
@@ -0,0 +1,116 @@
1
+ ---
2
+ name: ov-experience-memory
3
+ description: Retrieve and apply OpenViking Experience memories through the Agent runtime's generic OpenViking search and read tools. Use before or during executable, multi-step, or tool-based work such as coding, file or data changes, configuration, deployment, workflow execution, and failure recovery when prior operational guidance could improve reliability. Do not use for casual chat or simple factual questions.
4
+ ---
5
+
6
+ # OpenViking Experience Memory
7
+
8
+ Use prior task Experience as advisory operational guidance. Keep the current
9
+ user request, current environment, and verified tool results authoritative.
10
+ Experience retrieval supplements normal context retrieval; it does not replace
11
+ user memory, events, preferences, session archives, resources, or Agent Skills.
12
+
13
+ ## Preconditions
14
+
15
+ - Use only OpenViking tools that are actually registered in the current Agent
16
+ runtime.
17
+ - Require both a semantic search capability and an exact URI read capability.
18
+ - If either capability is unavailable, continue without Experience. Do not
19
+ invent a tool call, fabricate a ToolPart, or replace the Agent tool call with
20
+ direct HTTP or CLI access.
21
+ - Do not substitute broad memory `recall` for a search scoped to the Experience
22
+ root. Continue using the runtime's normal recall and retrieval flows when the
23
+ task also needs user facts, events, decisions, prior conversation, or domain
24
+ resources.
25
+
26
+ ## Select Runtime Tools
27
+
28
+ Choose the registered names that match the current runtime:
29
+
30
+ | Runtime | Search | Read |
31
+ | --- | --- | --- |
32
+ | OpenViking MCP, Codex, Claude Code | `find` or `search` | `read` |
33
+ | OpenCode | `openviking_find` or `openviking_search` | `openviking_read` |
34
+ | OpenClaw | `ov_search` | `ov_read` or `ov_multi_read` |
35
+
36
+ The host may display MCP names with a namespace such as
37
+ `mcp__openviking__find`. Use the exact registered name and schema shown by the
38
+ runtime. Prefer `find` for a fast task-start lookup and `search` when session
39
+ context or deeper intent analysis is useful.
40
+
41
+ ## Retrieval Workflow
42
+
43
+ 1. Decide whether the request is an executable task. Retrieve Experience for
44
+ planning, tool use, environment changes, multi-step workflows, or recovery
45
+ from a failed attempt. Skip retrieval for casual conversation and simple
46
+ knowledge answers.
47
+ 2. Build one concise query containing the task goal, domain object, intended
48
+ operation, and important constraints. After a failure, include the failed
49
+ operation and stable error signature.
50
+ 3. Search only the current user's Experience root:
51
+
52
+ ```text
53
+ viking://user/memories/experiences
54
+ ```
55
+
56
+ For tools using MCP-style parameters, set `target_uri` to this root. For
57
+ OpenClaw `ov_search`, set `uri` to this root. Never hardcode `default`,
58
+ `test`, or another user ID.
59
+ 4. Start with `limit=5` and the tool's normal score threshold. Judge results by
60
+ task, environment, preconditions, and likely effect; title similarity alone
61
+ is insufficient. If no result is relevant, continue without Experience and
62
+ do not broaden the search to unrelated memory directories.
63
+ 5. Select only the one to three Experience files likely to change execution.
64
+ Require an exact file URI without a query or fragment. Ignore directories,
65
+ unrelated memory types, and sidecars such as `.abstract.md`, `.overview.md`,
66
+ and `.relations.json`.
67
+ 6. Read every selected canonical `viking://.../memories/experiences/...` URI
68
+ with the runtime's OpenViking read tool. Search abstracts help selection but
69
+ are not a substitute for reading the Experience body.
70
+ 7. Apply relevant steps and checks while executing the task. Do not repeat the
71
+ Experience verbatim to the user unless its content is directly needed in the
72
+ answer.
73
+ 8. If execution fails for a materially new reason, perform at most one focused
74
+ follow-up search using the failure evidence, then read only newly relevant
75
+ Experience files.
76
+
77
+ ## Applying Retrieved Experience
78
+
79
+ - Treat Experience as reusable procedure, not as a user profile, user intent,
80
+ security policy, or proof that an action succeeded.
81
+ - Follow priority in this order: system and developer instructions, current
82
+ user request, current environment and tool evidence, then Experience.
83
+ - Ignore stale, incompatible, unsafe, or conflicting guidance. Verify commands,
84
+ paths, APIs, versions, and destructive actions against the current task.
85
+ - Preserve confirmation requirements and permission boundaries. Prior success
86
+ never authorizes a destructive or external action in the current session.
87
+ - When multiple Experience files conflict, prefer the one whose preconditions
88
+ match the current environment; otherwise proceed conservatively and surface
89
+ the ambiguity when it affects the user.
90
+
91
+ ## Session Evidence
92
+
93
+ Use real Agent tool calls so the committed OpenViking session retains their
94
+ ToolParts:
95
+
96
+ - A completed generic OpenViking `find`, `search`, or `list` result containing
97
+ an Experience URI records recall for that Experience.
98
+ - A completed generic OpenViking `read` or `multi_read` of an Experience URI
99
+ records injection and can associate the resulting trajectory with that
100
+ Experience.
101
+ - Failed, cancelled, or incomplete calls do not count.
102
+
103
+ Do not edit, summarize away, or synthesize these ToolParts before the session
104
+ is committed.
105
+
106
+ ## Example
107
+
108
+ For a request to fix a deployment failure:
109
+
110
+ 1. Search the Experience root with a query such as
111
+ `Kubernetes deployment image pull failure private registry`.
112
+ 2. Read the most relevant exact Experience URI.
113
+ 3. Check that its registry, credential, and rollout assumptions match the
114
+ current cluster.
115
+ 4. Apply the compatible diagnostic steps, verify the live result, and continue
116
+ the user's task.