diff --git a/config/hwlab-web-probe-sentinel/profiles.yaml b/config/hwlab-web-probe-sentinel/profiles.yaml index d6cb4396..1086e83a 100644 --- a/config/hwlab-web-probe-sentinel/profiles.yaml +++ b/config/hwlab-web-probe-sentinel/profiles.yaml @@ -195,8 +195,8 @@ nodes: baseImageRef: config/hwlab-node-control-plane.yaml#targets[1].tekton.toolsImage.output envRecipeRef: config/hwlab-web-probe-sentinel/profiles.yaml#nodes.${NODE}.sentinels.${nodeLower}-web-probe-sentinel.runtime targetValidation: - scenarioId: workbench-dsflash-go-single-turn-smoke - maxSeconds: 300 + scenarioId: workbench-dsflash-go-hwpod-two-turn-freeze-repro + maxSeconds: 360 serviceUnavailablePolicy: structured-failure secrets: sources: diff --git a/config/hwlab-web-probe-sentinel/scenarios.multi-sentinel.yaml b/config/hwlab-web-probe-sentinel/scenarios.multi-sentinel.yaml index ad2c3bf2..6b890f11 100644 --- a/config/hwlab-web-probe-sentinel/scenarios.multi-sentinel.yaml +++ b/config/hwlab-web-probe-sentinel/scenarios.multi-sentinel.yaml @@ -25,6 +25,26 @@ sentinel: promptSource: promptSet repeat: 1 + - id: workbench-dsflash-go-hwpod-two-turn-freeze-repro + enabled: true + cadence: 10m + observeTargetPath: /workbench + sampleIntervalMs: 1000 + screenshotIntervalMs: 60000 + maxRunSeconds: 360 + providerProfile: dsflash-go + providerProfileMode: exact + promptSetRef: config/hwlab-web-probe-sentinel/prompt-set.dsflash-go.yaml#sentinel.promptSet + reportViewRef: config/hwlab-web-probe-sentinel/report-views.multi-sentinel.yaml#sentinel.reportViews + commandSequence: + - type: newSession + - type: selectProvider + provider: dsflash-go + - type: sendPrompt + text: hi + - type: sendPrompt + text: 看看有什么hwpod可用 + - id: workbench-dsflash-go-tool-call-10x enabled: true cadence: 10m diff --git a/scripts/src/hwlab-node-web-sentinel-p5-observe.ts b/scripts/src/hwlab-node-web-sentinel-p5-observe.ts index 0646a661..7e9b0fed 100644 --- a/scripts/src/hwlab-node-web-sentinel-p5-observe.ts +++ b/scripts/src/hwlab-node-web-sentinel-p5-observe.ts @@ -61,7 +61,7 @@ export function runSentinelQuickVerify(state: SentinelCicdState, reason: string, const scenario = findScenario(state, scenarioId); if (scenario === null) return { ok: false, status: "blocked", reason: "scenario-not-found", scenarioId, valuesRedacted: true }; const commandSequence = arrayAt(scenario, "commandSequence").map(record); - const needsPromptSet = commandSequence.some((item) => stringAt(item, "type") === "sendPrompt"); + const needsPromptSet = commandSequence.some((item) => stringAt(item, "type") === "sendPrompt" && inlinePromptText(item) === null); const prompts = needsPromptSet ? readPromptSetForScenario(state, scenario) : { ok: true as const, prompts: [], summary: { source: "not-required", promptCount: 0, valuesRedacted: true } }; @@ -198,7 +198,7 @@ export function runSentinelQuickVerify(state: SentinelCicdState, reason: string, if (toAccountId !== null) args.push("--to-account-id", toAccountId); } if (type === "sendPrompt") { - args.push("--text", prompts.prompts[promptIndex % prompts.prompts.length] ?? ""); + args.push("--text", inlinePromptText(item) ?? prompts.prompts[promptIndex % prompts.prompts.length] ?? ""); args.push("--expected-action-wait-ms", String(numberAtNullable(item, "expectedActionWaitMs") ?? 45000)); promptIndex += 1; } @@ -437,6 +437,10 @@ function appendScenarioObserveCommandArgs(args: string[], item: Record): string | null { + return stringAtNullable(item, "text") ?? stringAtNullable(item, "prompt") ?? stringAtNullable(item, "value"); +} + function finalizeQuickVerifyFailure(state: SentinelCicdState, input: { readonly runId: string; readonly scenarioId: string; diff --git a/scripts/src/hwlab-node-web-sentinel-service.ts b/scripts/src/hwlab-node-web-sentinel-service.ts index 4e09dec7..c0387369 100644 --- a/scripts/src/hwlab-node-web-sentinel-service.ts +++ b/scripts/src/hwlab-node-web-sentinel-service.ts @@ -539,7 +539,11 @@ function buildObserveCommandPlan(config: WebProbeSentinelServiceConfig, scenario const type = stringAt(item, "type"); const argv = ["bun", "scripts/cli.ts", "web-probe", "observe", "command", "", "--type", type]; if (type === "selectProvider") argv.push("--provider", stringAt(item, "provider")); - if (type === "sendPrompt") argv.push("--text-stdin"); + if (type === "sendPrompt") { + const inlineText = inlinePromptText(item); + if (inlineText === null) argv.push("--text-stdin"); + else argv.push("--text", ""); + } if (type === "loginAccount" || type === "listSessions" || type === "logout") { const accountId = stringOrNull(item.accountId); if (accountId !== null) argv.push("--account-id", accountId); @@ -551,7 +555,7 @@ function buildObserveCommandPlan(config: WebProbeSentinelServiceConfig, scenario if (toAccountId !== null) argv.push("--to-account-id", toAccountId); } appendObserveCommandArgs(argv, item, { skipText: type === "sendPrompt" }); - return { phase: `observe-command-${type}`, argv, stdinSource: type === "sendPrompt" ? "prompt-source" : "none" } satisfies CommandPlanStep; + return { phase: `observe-command-${type}`, argv, stdinSource: type === "sendPrompt" ? inlinePromptText(item) === null ? "prompt-source" : "inline-text-redacted" : "none" } satisfies CommandPlanStep; }); const analyze: CommandPlanStep = { phase: "observe-analyze", @@ -561,6 +565,10 @@ function buildObserveCommandPlan(config: WebProbeSentinelServiceConfig, scenario return [start, ...commands, analyze]; } +function inlinePromptText(item: Record): string | null { + return stringOrNull(item.text) ?? stringOrNull(item.prompt) ?? stringOrNull(item.value); +} + function appendObserveCommandArgs(argv: string[], item: Record, options: { readonly skipText?: boolean } = {}): void { const mappings: readonly (readonly [string, string])[] = [ ["path", "--path"],