@abot-ai/runtime 1.1.0 → 1.2.0
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/README.md +6 -3
- package/dist/src/capabilities/tool-types.d.ts +1 -1
- package/dist/src/model-gateway/providers/ollama/generation-options.d.ts +1 -3
- package/dist/src/model-gateway/providers/ollama/generation-options.js +1 -5
- package/dist/src/model-gateway/providers/ollama/payload.js +0 -8
- package/dist/src/model-gateway/server/request-body.js +1 -0
- package/dist/src/plugin-sdk/index.d.ts +2 -0
- package/dist/src/plugin-sdk/index.js +2 -0
- package/dist/src/plugin-sdk/tool-availability-brief.d.ts +9 -0
- package/dist/src/plugin-sdk/tool-availability-brief.js +48 -0
- package/dist/src/plugin-sdk/tool-availability-overview.d.ts +9 -0
- package/dist/src/plugin-sdk/tool-availability-overview.js +62 -0
- package/dist/src/runtime/adapters/registered-tool-payload-plan.d.ts +0 -9
- package/dist/src/runtime/adapters/registered-tool-payload-plan.js +0 -67
- package/dist/src/runtime/adapters/registered-tool-payload-related-artifacts.d.ts +13 -0
- package/dist/src/runtime/adapters/registered-tool-payload-related-artifacts.js +84 -0
- package/dist/src/runtime/adapters/registered-tool-worker-capabilities/catalog.js +4 -0
- package/dist/src/runtime/adapters/registered-tool-worker-capabilities/execution.js +3 -0
- package/dist/src/runtime/adapters/registered-tool-worker-capabilities/payload-lifecycle.d.ts +1 -0
- package/dist/src/runtime/adapters/registered-tool-worker-capabilities/payload-lifecycle.js +11 -1
- package/dist/src/runtime/adapters/registered-tool-worker-capabilities/payload-stages.d.ts +1 -0
- package/dist/src/runtime/adapters/registered-tool-worker-capabilities/payload-stages.js +9 -1
- package/dist/src/runtime/capabilities/request-bound-tool-registry.js +1 -24
- package/dist/src/runtime/capabilities/tool-availability.d.ts +6 -0
- package/dist/src/runtime/capabilities/tool-availability.js +28 -0
- package/dist/src/runtime/context/capability-brief.d.ts +25 -0
- package/dist/src/runtime/context/capability-brief.js +106 -0
- package/dist/src/runtime/context/request-tool-results-message-binding.d.ts +6 -0
- package/dist/src/runtime/context/request-tool-results-message-binding.js +30 -0
- package/dist/src/runtime/context/request-tool-results-scope.d.ts +3 -0
- package/dist/src/runtime/context/request-tool-results-scope.js +8 -0
- package/dist/src/runtime/context/request-tool-results.d.ts +8 -4
- package/dist/src/runtime/context/request-tool-results.js +49 -38
- package/dist/src/runtime/orchestration/role-calls/candidate-validation.js +8 -1
- package/dist/src/runtime/orchestration/role-calls/child-return.d.ts +4 -0
- package/dist/src/runtime/orchestration/role-calls/child-return.js +25 -5
- package/dist/src/runtime/orchestration/role-calls/command-decoder.js +8 -3
- package/dist/src/runtime/orchestration/role-calls/command-dispatch/child-transitions.d.ts +1 -1
- package/dist/src/runtime/orchestration/role-calls/command-dispatch/child-transitions.js +17 -2
- package/dist/src/runtime/orchestration/role-calls/command-dispatch.d.ts +1 -1
- package/dist/src/runtime/orchestration/role-calls/command-dispatch.js +2 -2
- package/dist/src/runtime/orchestration/role-calls/contracts.d.ts +5 -2
- package/dist/src/runtime/orchestration/role-calls/contracts.js +4 -4
- package/dist/src/runtime/orchestration/role-calls/dependency-results.d.ts +1 -1
- package/dist/src/runtime/orchestration/role-calls/dependency-results.js +1 -0
- package/dist/src/runtime/orchestration/role-calls/index.d.ts +5 -1
- package/dist/src/runtime/orchestration/role-calls/index.js +5 -1
- package/dist/src/runtime/orchestration/role-calls/ledger.d.ts +3 -1
- package/dist/src/runtime/orchestration/role-calls/ledger.js +9 -2
- package/dist/src/runtime/orchestration/role-calls/reducer.d.ts +1 -1
- package/dist/src/runtime/orchestration/role-calls/reducer.js +2 -2
- package/dist/src/runtime/orchestration/role-calls/result-receipt.d.ts +49 -0
- package/dist/src/runtime/orchestration/role-calls/result-receipt.js +188 -0
- package/dist/src/runtime/orchestration/role-calls/return-result-receipt.d.ts +19 -0
- package/dist/src/runtime/orchestration/role-calls/return-result-receipt.js +52 -0
- package/dist/src/runtime/orchestration/role-calls/transactions.js +1 -0
- package/dist/src/runtime/orchestration/role-calls/work-result-lineage.d.ts +34 -0
- package/dist/src/runtime/orchestration/role-calls/work-result-lineage.js +185 -0
- package/dist/src/runtime/orchestration/role-calls/work-result-receipt.d.ts +36 -0
- package/dist/src/runtime/orchestration/role-calls/work-result-receipt.js +187 -0
- package/dist/src/runtime/orchestration/role-executors/activation/result-normalization.js +6 -3
- package/dist/src/runtime/orchestration/role-executors/child-invocation/transaction.js +1 -0
- package/dist/src/runtime/orchestration/role-executors/contracts.d.ts +2 -1
- package/dist/src/runtime/orchestration/worker-capabilities/assignment-provenance.d.ts +36 -0
- package/dist/src/runtime/orchestration/worker-capabilities/assignment-provenance.js +171 -0
- package/dist/src/runtime/orchestration/worker-capabilities/contracts.d.ts +32 -1
- package/dist/src/runtime/orchestration/worker-capabilities/execution/invocation-preparation.d.ts +2 -1
- package/dist/src/runtime/orchestration/worker-capabilities/execution/invocation-preparation.js +3 -0
- package/dist/src/runtime/orchestration/worker-capabilities/execution.js +42 -19
- package/dist/src/runtime/orchestration/worker-capabilities/index.d.ts +2 -0
- package/dist/src/runtime/orchestration/worker-capabilities/index.js +2 -0
- package/dist/src/runtime/orchestration/worker-capabilities/payload-assignment-validation.d.ts +3 -0
- package/dist/src/runtime/orchestration/worker-capabilities/payload-assignment-validation.js +30 -0
- package/dist/src/runtime/orchestration/worker-capabilities/payload-author.js +8 -19
- package/dist/src/runtime/orchestration/worker-capabilities/payload-contracts.d.ts +5 -1
- package/dist/src/runtime/orchestration/worker-capabilities/payload-instructions.js +1 -1
- package/dist/src/runtime/orchestration/worker-capabilities/payload-source-provenance.d.ts +14 -0
- package/dist/src/runtime/orchestration/worker-capabilities/payload-source-provenance.js +132 -0
- package/dist/src/runtime/request/capability-brief.d.ts +5 -0
- package/dist/src/runtime/request/capability-brief.js +24 -0
- package/dist/src/runtime/request/execution-scope.d.ts +2 -1
- package/dist/src/runtime/request/role-executor-composition.js +1 -1
- package/dist/src/runtime/request/worker-capability-composition.d.ts +2 -1
- package/dist/src/runtime/request/worker-capability-composition.js +6 -1
- package/dist/src/runtime/request/worker-capability-payload.js +11 -8
- package/dist/src/runtime/steps/execution-agent/prompt.js +4 -3
- package/dist/src/runtime/steps/planner-decision/capability-catalog-context.d.ts +14 -0
- package/dist/src/runtime/steps/planner-decision/capability-catalog-context.js +87 -0
- package/dist/src/runtime/steps/planner-decision/contracts.d.ts +3 -5
- package/dist/src/runtime/steps/planner-decision/contracts.js +3 -3
- package/dist/src/runtime/steps/planner-decision/format.d.ts +3 -2
- package/dist/src/runtime/steps/planner-decision/format.js +73 -76
- package/dist/src/runtime/steps/planner-decision/input.d.ts +4 -3
- package/dist/src/runtime/steps/planner-decision/input.js +10 -7
- package/dist/src/runtime/steps/planner-decision/parser.d.ts +3 -2
- package/dist/src/runtime/steps/planner-decision/parser.js +10 -19
- package/dist/src/runtime/steps/planner-decision/plan-parser.js +18 -12
- package/dist/src/runtime/steps/planner-decision/prompt.js +33 -28
- package/dist/src/runtime/steps/planner-decision/resume.d.ts +1 -1
- package/dist/src/runtime/steps/planner-decision/resume.js +38 -1
- package/dist/src/runtime/steps/planner-decision/run.d.ts +3 -2
- package/dist/src/runtime/steps/reviewer-decision/audit-coverage.d.ts +10 -0
- package/dist/src/runtime/steps/reviewer-decision/audit-coverage.js +186 -0
- package/dist/src/runtime/steps/reviewer-decision/contracts.d.ts +3 -8
- package/dist/src/runtime/steps/reviewer-decision/contracts.js +12 -6
- package/dist/src/runtime/steps/reviewer-decision/delegated-context.d.ts +24 -0
- package/dist/src/runtime/steps/reviewer-decision/delegated-context.js +70 -0
- package/dist/src/runtime/steps/reviewer-decision/diagnostics.js +1 -1
- package/dist/src/runtime/steps/reviewer-decision/format.js +37 -24
- package/dist/src/runtime/steps/reviewer-decision/input.js +1 -1
- package/dist/src/runtime/steps/reviewer-decision/model-context.d.ts +4 -3
- package/dist/src/runtime/steps/reviewer-decision/model-context.js +92 -10
- package/dist/src/runtime/steps/reviewer-decision/parser.js +19 -1
- package/dist/src/runtime/steps/reviewer-decision/projection.js +42 -68
- package/dist/src/runtime/steps/reviewer-decision/prompt.js +10 -5
- package/dist/src/runtime/steps/reviewer-decision/run.js +12 -3
- package/dist/src/runtime/steps/reviewer-decision/verification-coverage.d.ts +14 -0
- package/dist/src/runtime/steps/reviewer-decision/verification-coverage.js +52 -0
- package/dist/src/runtime/steps/supervisor-decision/capability-brief.d.ts +14 -0
- package/dist/src/runtime/steps/supervisor-decision/capability-brief.js +38 -0
- package/dist/src/runtime/steps/supervisor-decision/contracts.d.ts +7 -3
- package/dist/src/runtime/steps/supervisor-decision/diagnostics.d.ts +2 -0
- package/dist/src/runtime/steps/supervisor-decision/diagnostics.js +8 -2
- package/dist/src/runtime/steps/supervisor-decision/format.js +32 -20
- package/dist/src/runtime/steps/supervisor-decision/input.d.ts +4 -1
- package/dist/src/runtime/steps/supervisor-decision/input.js +19 -1
- package/dist/src/runtime/steps/supervisor-decision/parser.js +62 -59
- package/dist/src/runtime/steps/supervisor-decision/prompt.js +6 -7
- package/dist/src/runtime/steps/supervisor-decision/resume.js +47 -1
- package/dist/src/runtime/steps/supervisor-decision/run.js +10 -0
- package/dist/src/runtime/steps/supervisor-decision/working-directory.js +2 -1
- package/dist/src/runtime/steps/worker-decision/contracts.d.ts +2 -1
- package/dist/src/runtime/steps/worker-decision/input/canonical-state.js +8 -1
- package/dist/src/runtime/steps/worker-decision/input/diagnostic-projection.js +2 -2
- package/dist/src/runtime/steps/worker-decision/input/prompt-context.d.ts +1 -0
- package/dist/src/runtime/steps/worker-decision/input/prompt-context.js +4 -1
- package/dist/src/runtime/steps/worker-decision/input/reference-context.js +34 -14
- package/dist/src/runtime/steps/worker-decision/input/types.d.ts +2 -1
- package/dist/src/runtime/steps/worker-decision/input.d.ts +1 -0
- package/dist/src/runtime/steps/worker-decision/input.js +1 -0
- package/dist/src/runtime/steps/worker-decision/payload-dependency-results.d.ts +8 -0
- package/dist/src/runtime/steps/worker-decision/payload-dependency-results.js +19 -0
- package/dist/src/runtime/steps/worker-decision/prompt.js +8 -8
- package/dist/src/runtime/steps/worker-decision/result-author.js +18 -11
- package/dist/src/runtime/steps/worker-decision/run.js +2 -2
- package/dist/src/web-ui/app/ARCHITECTURE.md +19 -6
- package/dist/src/web-ui/app/app.js +6 -7
- package/dist/src/web-ui/app/components/composer-context-window.d.ts +25 -0
- package/dist/src/web-ui/app/components/composer-context-window.js +155 -0
- package/dist/src/web-ui/app/components/composer-plan.d.ts +9 -0
- package/dist/src/web-ui/app/components/composer-plan.js +128 -0
- package/dist/src/web-ui/app/components/conversation-activity.d.ts +5 -6
- package/dist/src/web-ui/app/components/conversation-activity.js +64 -157
- package/dist/src/web-ui/app/components/conversation-role-cards.d.ts +23 -0
- package/dist/src/web-ui/app/components/conversation-role-cards.js +181 -0
- package/dist/src/web-ui/app/components/conversation-sidebar-layout.js +12 -0
- package/dist/src/web-ui/app/components/conversation-sources.d.ts +7 -0
- package/dist/src/web-ui/app/components/conversation-sources.js +182 -0
- package/dist/src/web-ui/app/components/conversation-view.js +34 -6
- package/dist/src/web-ui/app/components/model-selector.js +4 -1
- package/dist/src/web-ui/app/components/operations-section.js +46 -0
- package/dist/src/web-ui/app/components/workspace-shell.js +86 -78
- package/dist/src/web-ui/app/controllers/realtime-event-controller.d.ts +1 -0
- package/dist/src/web-ui/app/controllers/realtime-event-controller.js +55 -90
- package/dist/src/web-ui/app/controllers/runtime-selection-controller.js +2 -0
- package/dist/src/web-ui/app/controllers/session-controller.js +17 -12
- package/dist/src/web-ui/app/index.html +209 -210
- package/dist/src/web-ui/app/lib/composer-plan-model.d.ts +32 -0
- package/dist/src/web-ui/app/lib/composer-plan-model.js +108 -0
- package/dist/src/web-ui/app/lib/conversation-role-model.d.ts +19 -0
- package/dist/src/web-ui/app/lib/conversation-role-model.js +193 -0
- package/dist/src/web-ui/app/lib/event-presentation.js +30 -9
- package/dist/src/web-ui/app/lib/source-url-policy.d.ts +2 -0
- package/dist/src/web-ui/app/lib/source-url-policy.js +31 -0
- package/dist/src/web-ui/app/lib/task-progress.d.ts +53 -0
- package/dist/src/web-ui/app/lib/task-progress.js +233 -0
- package/dist/src/web-ui/app/lib/tool-invocation-count.d.ts +5 -0
- package/dist/src/web-ui/app/lib/tool-invocation-count.js +21 -0
- package/dist/src/web-ui/app/lib/web-source-event.d.ts +8 -0
- package/dist/src/web-ui/app/lib/web-source-event.js +21 -0
- package/dist/src/web-ui/app/lib/web-sources.d.ts +36 -0
- package/dist/src/web-ui/app/lib/web-sources.js +177 -0
- package/dist/src/web-ui/app/styles/00-tokens-base.css +15 -3
- package/dist/src/web-ui/app/styles/10-shell-sessions.css +24 -34
- package/dist/src/web-ui/app/styles/12-conversation-sidebar.css +93 -0
- package/dist/src/web-ui/app/styles/20-chat-composer.css +55 -472
- package/dist/src/web-ui/app/styles/21-composer-controls.css +368 -0
- package/dist/src/web-ui/app/styles/22-composer-context-window.css +90 -0
- package/dist/src/web-ui/app/styles/23-composer-plan.css +171 -0
- package/dist/src/web-ui/app/styles/24-conversation-role-cards.css +205 -0
- package/dist/src/web-ui/app/styles/25-conversation-sources.css +141 -0
- package/dist/src/web-ui/app/styles/30-inspector-config.css +21 -209
- package/dist/src/web-ui/app/styles/35-memory-onboarding.css +8 -8
- package/dist/src/web-ui/app/styles/36-memory-management.css +13 -13
- package/dist/src/web-ui/app/styles/37-config-operations.css +197 -0
- package/dist/src/web-ui/app/styles/40-config-workspace.css +36 -36
- package/dist/src/web-ui/app/styles/90-responsive.css +14 -77
- package/dist/src/web-ui/app/styles/foundation.css +2 -2
- package/dist/src/web-ui/app/styles.css +7 -0
- package/dist/src/web-ui/app/ui-behavior.d.ts +1 -1
- package/dist/src/web-ui/app/ui-behavior.js +1 -1
- package/docs/configuration.md +15 -8
- package/docs/installation.md +7 -4
- package/docs/known-limitations.md +21 -0
- package/docs/plugins.md +28 -13
- package/docs/runtime-invariant-coverage.md +18 -17
- package/docs/runtime-prompt-policy-contracts.md +27 -17
- package/package.json +4 -3
- package/plugins/capability-brief/source/index.ts +5 -48
- package/plugins/capability-brief/src/index.cjs +46 -33
- package/plugins/system-probe/plugin.json +1 -0
- package/plugins/web/README.md +125 -0
- package/plugins/web/plugin.json +1 -1
- package/plugins/web/skills/web_fetch_skill/SKILL.md +2 -2
- package/plugins/web/skills/web_search_skill/SKILL.md +8 -4
- package/plugins/web/source/errors.ts +5 -1
- package/plugins/web/source/fetch-presentation.ts +61 -0
- package/plugins/web/source/fetch-service.ts +2 -31
- package/plugins/web/source/light/config.ts +196 -0
- package/plugins/web/source/light/crawl/origin-gate.ts +134 -0
- package/plugins/web/source/light/crawl/robots-cache.ts +71 -0
- package/plugins/web/source/light/crawl/robots-parser.ts +132 -0
- package/plugins/web/source/light/crawl/robots-policy.ts +154 -0
- package/plugins/web/source/light/crawl/session-budget.ts +141 -0
- package/plugins/web/source/light/crawl/transport.ts +216 -0
- package/plugins/web/source/light/discovery/candidate-values.ts +63 -0
- package/plugins/web/source/light/discovery/feed-document.ts +127 -0
- package/plugins/web/source/light/discovery/html-links.ts +80 -0
- package/plugins/web/source/light/discovery/html-robots-directives.ts +29 -0
- package/plugins/web/source/light/discovery/markup-tree.ts +145 -0
- package/plugins/web/source/light/discovery/origin-dates.ts +71 -0
- package/plugins/web/source/light/discovery/sitemap-document.ts +63 -0
- package/plugins/web/source/light/documents/cache-policy.ts +28 -0
- package/plugins/web/source/light/documents/document-cache.ts +99 -0
- package/plugins/web/source/light/documents/document-charset.ts +89 -0
- package/plugins/web/source/light/documents/document-contract.ts +20 -0
- package/plugins/web/source/light/documents/document-reader.ts +75 -0
- package/plugins/web/source/light/documents/extract-document.ts +124 -0
- package/plugins/web/source/light/documents/http-cache-freshness.ts +68 -0
- package/plugins/web/source/light/documents/response-decoding.ts +120 -0
- package/plugins/web/source/light/ranking/document-ranking.ts +114 -0
- package/plugins/web/source/light/ranking/query-normalization.ts +69 -0
- package/plugins/web/source/light/search-collection.ts +136 -0
- package/plugins/web/source/light/search-frontier.ts +246 -0
- package/plugins/web/source/light/search-metadata.ts +84 -0
- package/plugins/web/source/light/search-service.ts +154 -0
- package/plugins/web/source/light/search-unavailable.ts +33 -0
- package/plugins/web/source/light/sources/catalog.ts +312 -0
- package/plugins/web/source/light/sources/source-definition.ts +9 -0
- package/plugins/web/source/light/sources/source-selection.ts +35 -0
- package/plugins/web/source/plugin.ts +70 -56
- package/plugins/web/source/public-http.ts +10 -1
- package/plugins/web/source/search-presentation.ts +63 -63
- package/plugins/web/source/search-service-selector.ts +31 -0
- package/plugins/web/source/search-service.ts +6 -0
- package/plugins/web/source/search-source-presentation.ts +76 -0
- package/plugins/web/source/search-types.ts +4 -0
- package/plugins/web/source/source-output-receipts.ts +267 -0
- package/plugins/web/source/source-receipt-budget.ts +51 -0
- package/plugins/web/source/source-receipt-contract.ts +18 -0
- package/plugins/web/src/index.cjs +3214 -288
- package/src/runtime/README.md +30 -9
- package/dist/src/model-gateway/structured-output/budget.d.ts +0 -7
- package/dist/src/model-gateway/structured-output/budget.js +0 -20
- package/dist/src/model-gateway/structured-output/schema-character-estimator.d.ts +0 -1
- package/dist/src/model-gateway/structured-output/schema-character-estimator.js +0 -211
- package/dist/src/model-gateway/structured-output-budget.d.ts +0 -1
- package/dist/src/model-gateway/structured-output-budget.js +0 -1
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import {
|
|
2
|
+
eventTone,
|
|
3
|
+
formatEventDetail,
|
|
4
|
+
formatEventLabel,
|
|
5
|
+
titleCaseEventValue,
|
|
6
|
+
} from "./event-presentation.js";
|
|
7
|
+
import { textOf } from "./text-format.js";
|
|
8
|
+
import { countToolInvocations } from "./tool-invocation-count.js";
|
|
9
|
+
|
|
10
|
+
const ROLE_TITLES = Object.freeze({
|
|
11
|
+
supervisor: "Supervisor",
|
|
12
|
+
planner: "Planner",
|
|
13
|
+
worker: "Worker",
|
|
14
|
+
reviewer: "Reviewer",
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const ROLE_RESPONSIBILITIES = Object.freeze({
|
|
18
|
+
supervisor: "Coordinates the request",
|
|
19
|
+
planner: "Plans the work",
|
|
20
|
+
worker: "Performs assigned tasks",
|
|
21
|
+
reviewer: "Reviews the result",
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
function latestRoleAction(group) {
|
|
25
|
+
const toolEvent = group.toolEvents.at(-1);
|
|
26
|
+
return roleActivitySummary(toolEvent || group.latestEvent);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function belongsToRoleRequest(event, requestId) {
|
|
30
|
+
if (!event || typeof event !== "object") return false;
|
|
31
|
+
return textOf(event.requestId) === requestId;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function activityPosition(event) {
|
|
35
|
+
if (Number.isSafeInteger(event.eventSequence) && event.eventSequence > 0) {
|
|
36
|
+
return { domain: "runtime", value: event.eventSequence };
|
|
37
|
+
}
|
|
38
|
+
const replaySequence = event.lastSeqNo ?? event.seqNo;
|
|
39
|
+
if (Number.isSafeInteger(replaySequence) && replaySequence > 0) {
|
|
40
|
+
return { domain: "replay", value: replaySequence };
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function orderedRequestActivity(events, requestId) {
|
|
46
|
+
const unique = [];
|
|
47
|
+
const seen = new Set();
|
|
48
|
+
const domains = new Map();
|
|
49
|
+
for (const event of events) {
|
|
50
|
+
if (!belongsToRoleRequest(event, requestId)) continue;
|
|
51
|
+
const position = activityPosition(event);
|
|
52
|
+
if (!position) {
|
|
53
|
+
unique.push({ event, position });
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const identity = `${position.domain}:${position.value}`;
|
|
57
|
+
if (seen.has(identity)) continue;
|
|
58
|
+
seen.add(identity);
|
|
59
|
+
unique.push({ event, position });
|
|
60
|
+
const domain = domains.get(position.domain) || { events: [], next: 0 };
|
|
61
|
+
domain.events.push({ event, position });
|
|
62
|
+
domains.set(position.domain, domain);
|
|
63
|
+
}
|
|
64
|
+
for (const domain of domains.values()) {
|
|
65
|
+
domain.events.sort(
|
|
66
|
+
(left, right) => left.position.value - right.position.value,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
// Runtime and replay cursors are separate counters. Sort only within each
|
|
70
|
+
// counter's existing slots, retaining arrival order for unsequenced history.
|
|
71
|
+
return unique.map(({ event, position }) => {
|
|
72
|
+
if (!position) return event;
|
|
73
|
+
const domain = domains.get(position.domain);
|
|
74
|
+
return domain.events[domain.next++].event;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function activityEventName(event) {
|
|
79
|
+
return textOf(event.eventName || event.name || event.rawType || event.type);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function isRequestTerminalEvent(event) {
|
|
83
|
+
if (event.type === "completed" || event.type === "failed") return true;
|
|
84
|
+
const name = activityEventName(event);
|
|
85
|
+
return name === "request.completed" || name === "request.failed";
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function isToolActivityEvent(event) {
|
|
89
|
+
return activityEventName(event).startsWith("tool.");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function hasSupportedRoleStage(stage) {
|
|
93
|
+
return Object.hasOwn(ROLE_TITLES, stage);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function isFailedRoleActivity(event) {
|
|
97
|
+
return (textOf(event.tone) || eventTone(event)) === "failed";
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function roleActivitySummary(event) {
|
|
101
|
+
return (
|
|
102
|
+
textOf(event.summary).trim() ||
|
|
103
|
+
formatEventDetail(event) ||
|
|
104
|
+
formatEventLabel(event)
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function createRoleGroup(role, event) {
|
|
109
|
+
return { role, phase: "", latestEvent: event, toolEvents: [] };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isActiveRoleActivity(group, activeRole, streaming) {
|
|
113
|
+
if (!streaming) return false;
|
|
114
|
+
if (group.role !== activeRole) return false;
|
|
115
|
+
return !isFailedRoleActivity(group.latestEvent);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function canShowActiveRoles(streaming, terminalSeen) {
|
|
119
|
+
if (terminalSeen) return false;
|
|
120
|
+
return streaming;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function buildRoleCard(group, activeRole, streaming) {
|
|
124
|
+
const failed = isFailedRoleActivity(group.latestEvent);
|
|
125
|
+
const active = isActiveRoleActivity(group, activeRole, streaming);
|
|
126
|
+
const toolCount = countToolInvocations(group.toolEvents);
|
|
127
|
+
let tone = "recorded";
|
|
128
|
+
if (active) tone = "active";
|
|
129
|
+
if (failed) tone = "failed";
|
|
130
|
+
return {
|
|
131
|
+
id: group.role,
|
|
132
|
+
role: group.role,
|
|
133
|
+
title: ROLE_TITLES[group.role],
|
|
134
|
+
responsibility: ROLE_RESPONSIBILITIES[group.role],
|
|
135
|
+
phaseLabel: titleCaseEventValue(group.phase),
|
|
136
|
+
summary: latestRoleAction(group),
|
|
137
|
+
facts:
|
|
138
|
+
toolCount > 0
|
|
139
|
+
? [`${toolCount} tool call${toolCount === 1 ? "" : "s"}`]
|
|
140
|
+
: [],
|
|
141
|
+
active,
|
|
142
|
+
tone,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function buildConversationRoleCards({
|
|
147
|
+
requestId,
|
|
148
|
+
events = [],
|
|
149
|
+
streaming = false,
|
|
150
|
+
} = {}) {
|
|
151
|
+
const normalizedRequestId = textOf(requestId).trim();
|
|
152
|
+
if (!normalizedRequestId) return [];
|
|
153
|
+
|
|
154
|
+
const groups = new Map();
|
|
155
|
+
let activeRole = "";
|
|
156
|
+
let terminalSeen = false;
|
|
157
|
+
const activityEvents = Array.isArray(events) ? events : [];
|
|
158
|
+
for (const event of orderedRequestActivity(
|
|
159
|
+
activityEvents,
|
|
160
|
+
normalizedRequestId,
|
|
161
|
+
)) {
|
|
162
|
+
if (isRequestTerminalEvent(event)) {
|
|
163
|
+
terminalSeen = true;
|
|
164
|
+
activeRole = "";
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const stage = textOf(event.stage).trim();
|
|
169
|
+
if (stage) {
|
|
170
|
+
activeRole = "";
|
|
171
|
+
if (!hasSupportedRoleStage(stage)) continue;
|
|
172
|
+
activeRole = stage;
|
|
173
|
+
const group = groups.get(stage) || createRoleGroup(stage, event);
|
|
174
|
+
group.phase = textOf(event.phase);
|
|
175
|
+
group.latestEvent = event;
|
|
176
|
+
groups.set(stage, group);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (!activeRole) continue;
|
|
180
|
+
if (!isToolActivityEvent(event)) continue;
|
|
181
|
+
const group = groups.get(activeRole);
|
|
182
|
+
group.latestEvent = event;
|
|
183
|
+
group.toolEvents.push({ ...event, eventName: activityEventName(event) });
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return [...groups.values()].map((group) =>
|
|
187
|
+
buildRoleCard(
|
|
188
|
+
group,
|
|
189
|
+
activeRole,
|
|
190
|
+
canShowActiveRoles(streaming, terminalSeen),
|
|
191
|
+
),
|
|
192
|
+
);
|
|
193
|
+
}
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { textOf } from "./text-format.js";
|
|
2
2
|
|
|
3
|
+
function canMergeEventTimelineEntries(previous, event, name, summary) {
|
|
4
|
+
if (!previous) return false;
|
|
5
|
+
if (previous.name !== name) return false;
|
|
6
|
+
if (previous.summary !== summary) return false;
|
|
7
|
+
if (previous.tone !== event.tone) return false;
|
|
8
|
+
if (textOf(previous.requestId) !== textOf(event.requestId)) return false;
|
|
9
|
+
if (textOf(previous.stage) !== textOf(event.stage)) return false;
|
|
10
|
+
return textOf(previous.phase) === textOf(event.phase);
|
|
11
|
+
}
|
|
12
|
+
|
|
3
13
|
export function buildEventTimelineEntries(events) {
|
|
4
14
|
const entries = [];
|
|
5
15
|
for (const event of events) {
|
|
@@ -7,13 +17,15 @@ export function buildEventTimelineEntries(events) {
|
|
|
7
17
|
if (!name) continue;
|
|
8
18
|
const summary = textOf(event.summary);
|
|
9
19
|
const previous = entries[entries.length - 1];
|
|
10
|
-
if (
|
|
11
|
-
previous &&
|
|
12
|
-
previous.name === name &&
|
|
13
|
-
previous.summary === summary &&
|
|
14
|
-
previous.tone === event.tone
|
|
15
|
-
) {
|
|
20
|
+
if (canMergeEventTimelineEntries(previous, event, name, summary)) {
|
|
16
21
|
previous.count = (previous.count || 1) + (event.count || 1);
|
|
22
|
+
if (typeof event.eventSequence === "number")
|
|
23
|
+
previous.eventSequence = Math.max(
|
|
24
|
+
previous.eventSequence ?? 0,
|
|
25
|
+
event.eventSequence,
|
|
26
|
+
);
|
|
27
|
+
if (typeof event.lastSeqNo === "number")
|
|
28
|
+
previous.lastSeqNo = event.lastSeqNo;
|
|
17
29
|
continue;
|
|
18
30
|
}
|
|
19
31
|
entries.push({
|
|
@@ -241,8 +253,17 @@ export function eventKeyFor(message, label, tone) {
|
|
|
241
253
|
const tool = textOf(message.tool);
|
|
242
254
|
const approvalId = textOf(message.approvalId);
|
|
243
255
|
const status = textOf(message.status);
|
|
256
|
+
const stage = textOf(message.stage);
|
|
244
257
|
const phase = textOf(message.phase);
|
|
245
|
-
return [
|
|
246
|
-
|
|
247
|
-
|
|
258
|
+
return JSON.stringify([
|
|
259
|
+
requestId,
|
|
260
|
+
name,
|
|
261
|
+
label,
|
|
262
|
+
tone,
|
|
263
|
+
tool,
|
|
264
|
+
approvalId,
|
|
265
|
+
status,
|
|
266
|
+
stage,
|
|
267
|
+
phase,
|
|
268
|
+
]);
|
|
248
269
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const MAX_SOURCE_URL_LENGTH = 4_096;
|
|
2
|
+
|
|
3
|
+
export function parseWebSourceUrl(value) {
|
|
4
|
+
if (typeof value !== "string") return null;
|
|
5
|
+
const candidate = value.trim();
|
|
6
|
+
if (!candidate || candidate.length > MAX_SOURCE_URL_LENGTH) return null;
|
|
7
|
+
if (/[\u0000-\u0020\u007f]/u.test(candidate)) return null;
|
|
8
|
+
try {
|
|
9
|
+
const url = new URL(candidate);
|
|
10
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
11
|
+
if (url.username || url.password) return null;
|
|
12
|
+
return url;
|
|
13
|
+
} catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function canLoadOriginIcon(hostname) {
|
|
19
|
+
const host = hostname.toLowerCase().replace(/\.$/u, "");
|
|
20
|
+
if (!host.includes(".")) return false;
|
|
21
|
+
if (host.startsWith("[")) return false;
|
|
22
|
+
if (/^\d+(?:\.\d+){3}$/u.test(host)) return false;
|
|
23
|
+
const localSuffixes = [".localhost", ".local", ".internal", ".home", ".lan"];
|
|
24
|
+
return !localSuffixes.some((suffix) => host.endsWith(suffix));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function webSourceFaviconUrl(value) {
|
|
28
|
+
const url = parseWebSourceUrl(value);
|
|
29
|
+
if (!url || !canLoadOriginIcon(url.hostname)) return "";
|
|
30
|
+
return `${url.origin}/favicon.ico`;
|
|
31
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { EventRecord } from "./event-presentation.js";
|
|
2
|
+
|
|
3
|
+
export interface TaskProgressItem {
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
status: "pending" | "in_progress" | "done" | "blocked";
|
|
7
|
+
order: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface PlanEventPosition {
|
|
11
|
+
source: "eventSequence" | "seqNo";
|
|
12
|
+
value: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface PlanItemUpdate {
|
|
16
|
+
item: TaskProgressItem;
|
|
17
|
+
position?: PlanEventPosition;
|
|
18
|
+
planSummary?: string;
|
|
19
|
+
planTotal?: number;
|
|
20
|
+
planCompleted?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface PlanReplayState {
|
|
24
|
+
snapshot?: {
|
|
25
|
+
summary: string;
|
|
26
|
+
total: number;
|
|
27
|
+
completed: number;
|
|
28
|
+
items: TaskProgressItem[];
|
|
29
|
+
hasSnapshot: boolean;
|
|
30
|
+
};
|
|
31
|
+
snapshotPosition?: PlanEventPosition;
|
|
32
|
+
itemUpdates: PlanItemUpdate[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface TaskProgress {
|
|
36
|
+
requestId: string;
|
|
37
|
+
summary: string;
|
|
38
|
+
total: number;
|
|
39
|
+
completed: number;
|
|
40
|
+
items: TaskProgressItem[];
|
|
41
|
+
activeItem: string;
|
|
42
|
+
hasSignal: boolean;
|
|
43
|
+
hasSnapshot: boolean;
|
|
44
|
+
lastEventSequence?: number;
|
|
45
|
+
lastSeqNo?: number;
|
|
46
|
+
replayState?: PlanReplayState;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export declare function taskStatusClass(status: unknown): string;
|
|
50
|
+
export declare function reduceTaskProgress(
|
|
51
|
+
current: TaskProgress | undefined,
|
|
52
|
+
message: EventRecord,
|
|
53
|
+
): TaskProgress | undefined;
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getPlanItemPayload,
|
|
3
|
+
getPlanPayload,
|
|
4
|
+
getRecord,
|
|
5
|
+
} from "./event-presentation.js";
|
|
6
|
+
import { textOf } from "./text-format.js";
|
|
7
|
+
|
|
8
|
+
const PLAN_ITEM_STATUSES = new Set([
|
|
9
|
+
"pending",
|
|
10
|
+
"in_progress",
|
|
11
|
+
"done",
|
|
12
|
+
"blocked",
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
export function taskStatusClass(status) {
|
|
16
|
+
const normalized = textOf(status).trim().toLowerCase();
|
|
17
|
+
if (normalized === "done" || normalized === "completed") return "done";
|
|
18
|
+
if (normalized === "in_progress" || normalized === "active") return "active";
|
|
19
|
+
if (normalized === "blocked" || normalized === "failed") return "failed";
|
|
20
|
+
if (normalized === "superseded") return "muted";
|
|
21
|
+
return "pending";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function isTaskProgressCount(value) {
|
|
25
|
+
return Number.isInteger(value) && value >= 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function hasValidPlanItem(item) {
|
|
29
|
+
if (!getRecord(item)) return false;
|
|
30
|
+
if (typeof item.title !== "string" || !item.title.trim()) return false;
|
|
31
|
+
return PLAN_ITEM_STATUSES.has(item.status);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function hasValidPlanSnapshot(plan) {
|
|
35
|
+
if (!Array.isArray(plan.items)) return false;
|
|
36
|
+
if (!plan.items.every(hasValidPlanItem)) return false;
|
|
37
|
+
if (plan.total !== undefined && !isTaskProgressCount(plan.total))
|
|
38
|
+
return false;
|
|
39
|
+
if (plan.completed !== undefined && !isTaskProgressCount(plan.completed)) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
const total = plan.total ?? plan.items.length;
|
|
43
|
+
if (total < plan.items.length) return false;
|
|
44
|
+
return (plan.completed ?? 0) <= total;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function isPlanEventForRequest(current, message) {
|
|
48
|
+
if (message.type !== "event") return false;
|
|
49
|
+
if (typeof message.requestId !== "string" || !message.requestId.trim()) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
if (current && current.requestId !== message.requestId) return false;
|
|
53
|
+
if (message.stage === "development_plan") return true;
|
|
54
|
+
return textOf(message.name).startsWith("planner.plan.");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function planEventPosition(message) {
|
|
58
|
+
if (isTaskProgressCount(message.eventSequence)) {
|
|
59
|
+
return { source: "eventSequence", value: message.eventSequence };
|
|
60
|
+
}
|
|
61
|
+
if (isTaskProgressCount(message.seqNo)) {
|
|
62
|
+
return { source: "seqNo", value: message.seqNo };
|
|
63
|
+
}
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function comparePlanEventPositions(left, right) {
|
|
68
|
+
if (!left || !right) return undefined;
|
|
69
|
+
if (left.source !== right.source) return undefined;
|
|
70
|
+
return left.value - right.value;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function isCoveredPlanEvent(position, baseline) {
|
|
74
|
+
const comparison = comparePlanEventPositions(position, baseline);
|
|
75
|
+
return comparison !== undefined && comparison <= 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function isLaterPlanEvent(position, baseline) {
|
|
79
|
+
const comparison = comparePlanEventPositions(position, baseline);
|
|
80
|
+
return comparison !== undefined && comparison > 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function planEventSequence(current, message) {
|
|
84
|
+
if (isTaskProgressCount(message.eventSequence)) {
|
|
85
|
+
return {
|
|
86
|
+
lastEventSequence: Math.max(
|
|
87
|
+
current?.lastEventSequence ?? 0,
|
|
88
|
+
message.eventSequence,
|
|
89
|
+
),
|
|
90
|
+
lastSeqNo: current?.lastSeqNo,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
lastEventSequence: current?.lastEventSequence,
|
|
95
|
+
lastSeqNo: isTaskProgressCount(message.seqNo)
|
|
96
|
+
? Math.max(current?.lastSeqNo ?? 0, message.seqNo)
|
|
97
|
+
: current?.lastSeqNo,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function orderPlanItems(items) {
|
|
102
|
+
return [...items].sort((left, right) => {
|
|
103
|
+
const leftOrder = left.order > 0 ? left.order : Infinity;
|
|
104
|
+
const rightOrder = right.order > 0 ? right.order : Infinity;
|
|
105
|
+
return leftOrder - rightOrder;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function findPlanItemIndex(items, nextItem) {
|
|
110
|
+
const nextId = nextItem.id.trim();
|
|
111
|
+
if (nextId) {
|
|
112
|
+
const idIndex = items.findIndex((item) => item.id.trim() === nextId);
|
|
113
|
+
if (idIndex >= 0) return idIndex;
|
|
114
|
+
}
|
|
115
|
+
const nextTitle = nextItem.title.trim().toLowerCase();
|
|
116
|
+
return items.findIndex((item) => {
|
|
117
|
+
if (nextId && item.id.trim()) return false;
|
|
118
|
+
return item.title.trim().toLowerCase() === nextTitle;
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function projectPlanItemUpdate(current, message) {
|
|
123
|
+
if (!hasValidPlanItem(message.item)) return null;
|
|
124
|
+
const item = getPlanItemPayload(message);
|
|
125
|
+
const items = [...(current?.items || [])];
|
|
126
|
+
const index = findPlanItemIndex(items, item);
|
|
127
|
+
const previousItem = items[index];
|
|
128
|
+
const nextItem = {
|
|
129
|
+
...item,
|
|
130
|
+
id: item.id || previousItem?.id || "",
|
|
131
|
+
order: item.order || previousItem?.order || 0,
|
|
132
|
+
};
|
|
133
|
+
if (index < 0) items.push(nextItem);
|
|
134
|
+
else items[index] = nextItem;
|
|
135
|
+
|
|
136
|
+
const total = isTaskProgressCount(message.planTotal)
|
|
137
|
+
? message.planTotal
|
|
138
|
+
: Math.max(current?.total || 0, items.length);
|
|
139
|
+
const statusChange =
|
|
140
|
+
Number(nextItem.status === "done") -
|
|
141
|
+
Number(previousItem?.status === "done");
|
|
142
|
+
const completed = isTaskProgressCount(message.planCompleted)
|
|
143
|
+
? message.planCompleted
|
|
144
|
+
: Math.max(0, (current?.completed || 0) + statusChange);
|
|
145
|
+
return {
|
|
146
|
+
summary: textOf(message.planSummary, current?.summary || ""),
|
|
147
|
+
total,
|
|
148
|
+
completed,
|
|
149
|
+
items,
|
|
150
|
+
hasSnapshot: current?.hasSnapshot || false,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function normalizedPlanItemUpdate(message, position) {
|
|
155
|
+
return {
|
|
156
|
+
item: getPlanItemPayload(message),
|
|
157
|
+
position,
|
|
158
|
+
...(typeof message.planSummary === "string"
|
|
159
|
+
? { planSummary: message.planSummary }
|
|
160
|
+
: {}),
|
|
161
|
+
...(isTaskProgressCount(message.planTotal)
|
|
162
|
+
? { planTotal: message.planTotal }
|
|
163
|
+
: {}),
|
|
164
|
+
...(isTaskProgressCount(message.planCompleted)
|
|
165
|
+
? { planCompleted: message.planCompleted }
|
|
166
|
+
: {}),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function orderPlanItemUpdates(updates) {
|
|
171
|
+
return [...updates].sort(
|
|
172
|
+
(left, right) =>
|
|
173
|
+
comparePlanEventPositions(left.position, right.position) ?? 0,
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function hasRetainedPlanEvent(updates, position) {
|
|
178
|
+
return updates.some(
|
|
179
|
+
(update) => comparePlanEventPositions(update.position, position) === 0,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function reducePlanReplayState(current, message, rawPlan) {
|
|
184
|
+
const replay = current?.replayState || { itemUpdates: [] };
|
|
185
|
+
const position = planEventPosition(message);
|
|
186
|
+
if (isCoveredPlanEvent(position, replay.snapshotPosition)) return null;
|
|
187
|
+
if (rawPlan) {
|
|
188
|
+
return {
|
|
189
|
+
snapshot: { ...getPlanPayload(message), hasSnapshot: true },
|
|
190
|
+
snapshotPosition: position,
|
|
191
|
+
itemUpdates: replay.itemUpdates.filter((update) =>
|
|
192
|
+
isLaterPlanEvent(update.position, position),
|
|
193
|
+
),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
if (!hasValidPlanItem(message.item)) return null;
|
|
197
|
+
if (hasRetainedPlanEvent(replay.itemUpdates, position)) return null;
|
|
198
|
+
const update = normalizedPlanItemUpdate(message, position);
|
|
199
|
+
// Intermediate item states matter when legacy deltas omit plan counters.
|
|
200
|
+
// Keep normalized deltas only until an authoritative snapshot covers them.
|
|
201
|
+
return {
|
|
202
|
+
...replay,
|
|
203
|
+
itemUpdates: orderPlanItemUpdates([...replay.itemUpdates, update]),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function projectPlanReplayState(replay) {
|
|
208
|
+
let projection = replay.snapshot;
|
|
209
|
+
for (const update of replay.itemUpdates) {
|
|
210
|
+
projection = projectPlanItemUpdate(projection, update);
|
|
211
|
+
}
|
|
212
|
+
return projection;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export function reduceTaskProgress(current, message) {
|
|
216
|
+
if (!isPlanEventForRequest(current, message)) return current;
|
|
217
|
+
const rawPlan = getRecord(message.plan);
|
|
218
|
+
if (rawPlan && !hasValidPlanSnapshot(rawPlan)) return current;
|
|
219
|
+
const replayState = reducePlanReplayState(current, message, rawPlan);
|
|
220
|
+
if (!replayState) return current;
|
|
221
|
+
const projection = projectPlanReplayState(replayState);
|
|
222
|
+
const items = orderPlanItems(projection.items);
|
|
223
|
+
return {
|
|
224
|
+
...projection,
|
|
225
|
+
requestId: message.requestId,
|
|
226
|
+
items,
|
|
227
|
+
activeItem:
|
|
228
|
+
items.find((item) => item.status === "in_progress")?.title || "",
|
|
229
|
+
hasSignal: true,
|
|
230
|
+
...planEventSequence(current, message),
|
|
231
|
+
replayState,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
function isToolInvocationStart(event) {
|
|
2
|
+
return event.eventName === "tool.started";
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function hasFiniteInvocationMultiplicity(value) {
|
|
6
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function toolInvocationMultiplicity(event) {
|
|
10
|
+
if (!hasFiniteInvocationMultiplicity(event.count)) return 1;
|
|
11
|
+
return Math.max(1, event.count);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function countToolInvocations(events) {
|
|
15
|
+
let count = 0;
|
|
16
|
+
for (const event of events) {
|
|
17
|
+
if (!isToolInvocationStart(event)) continue;
|
|
18
|
+
count += toolInvocationMultiplicity(event);
|
|
19
|
+
}
|
|
20
|
+
return count;
|
|
21
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { normalizeWebSources } from "./web-sources.js";
|
|
2
|
+
import type { normalizeLegacyWebSources } from "./web-sources.js";
|
|
3
|
+
|
|
4
|
+
export declare function projectWebSourceEvent(
|
|
5
|
+
message: Record<string, unknown>,
|
|
6
|
+
):
|
|
7
|
+
| ReturnType<typeof normalizeWebSources>
|
|
8
|
+
| ReturnType<typeof normalizeLegacyWebSources>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
normalizeLegacyWebSources,
|
|
3
|
+
normalizeWebSources,
|
|
4
|
+
} from "./web-sources.js";
|
|
5
|
+
|
|
6
|
+
function isCompletedWebTool(message) {
|
|
7
|
+
const name = message.name || message.rawType || message.type;
|
|
8
|
+
if (name !== "tool.completed") return false;
|
|
9
|
+
if (message.ok !== true) return false;
|
|
10
|
+
return message.tool === "web_search" || message.tool === "web_fetch";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function projectWebSourceEvent(message) {
|
|
14
|
+
if (!isCompletedWebTool(message)) return null;
|
|
15
|
+
const meta = message.meta;
|
|
16
|
+
if (!meta || typeof meta !== "object" || Array.isArray(meta)) return null;
|
|
17
|
+
if (Object.hasOwn(meta, "webSources")) {
|
|
18
|
+
return normalizeWebSources(meta.webSources, message.tool);
|
|
19
|
+
}
|
|
20
|
+
return normalizeLegacyWebSources(meta, message.tool);
|
|
21
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type WebSourceRetrieval = "not_attempted" | "retrieved" | "failed";
|
|
2
|
+
export type WebSourcePresentation =
|
|
3
|
+
| "omitted"
|
|
4
|
+
| "reference"
|
|
5
|
+
| "snippet"
|
|
6
|
+
| "content";
|
|
7
|
+
export type WebSource = {
|
|
8
|
+
url: string;
|
|
9
|
+
requestedUrl?: string;
|
|
10
|
+
title: string;
|
|
11
|
+
retrieval: WebSourceRetrieval;
|
|
12
|
+
presentation: WebSourcePresentation | "unknown";
|
|
13
|
+
contentTruncated: boolean;
|
|
14
|
+
};
|
|
15
|
+
export type WebSourcesReceipt = {
|
|
16
|
+
version: 0 | 1;
|
|
17
|
+
operation: "search" | "fetch";
|
|
18
|
+
provider?: "brave" | "light";
|
|
19
|
+
sources: WebSource[];
|
|
20
|
+
omittedSourceCount?: number;
|
|
21
|
+
};
|
|
22
|
+
export type ConversationSourcesGroup = WebSourcesReceipt & {
|
|
23
|
+
id: string;
|
|
24
|
+
callId: string;
|
|
25
|
+
};
|
|
26
|
+
export declare function normalizeWebSources(
|
|
27
|
+
value: unknown,
|
|
28
|
+
toolName: unknown,
|
|
29
|
+
): WebSourcesReceipt | null;
|
|
30
|
+
export declare function normalizeLegacyWebSources(
|
|
31
|
+
value: unknown,
|
|
32
|
+
toolName: unknown,
|
|
33
|
+
): WebSourcesReceipt | null;
|
|
34
|
+
export declare function buildConversationSources(
|
|
35
|
+
events?: unknown[],
|
|
36
|
+
): ConversationSourcesGroup[];
|